From 45b5ebaacf8ae1298987e0eb17e081a70bb99eda Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Thu, 25 Jun 2026 15:41:48 -0700 Subject: [PATCH 01/21] Add Jira creation to beta workflow --- ...ublish_image_autoinstrumentation_beta.yaml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 4713433bb..b419dc1de 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -97,6 +97,77 @@ jobs: with: sarif_file: sarif.output.json + - name: Parse SARIF for Critical/High CVEs + id: parse-cves + run: | + # Extract CVEs from SARIF + jq -r '.runs[0].results[] | + select(.level == "error" or .level == "warning") | + @json' sarif.output.json > vulnerabilities.json + + # Count vulnerabilities + echo "count=$(jq -s 'length' vulnerabilities.json)" >> $GITHUB_OUTPUT + + - name: Create Jira tickets with actionable details + if: steps.parse-cves.outputs.count > 0 + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + run: | + while IFS= read -r vuln; do + CVE=$(echo "$vuln" | jq -r '.ruleId') + PACKAGE=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.artifactLocation.uri // "unknown"') + VERSION=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.region.snippet.text // "unknown"') + MESSAGE=$(echo "$vuln" | jq -r '.message.text') + SEVERITY=$(echo "$vuln" | jq -r '.level') + + # Create comprehensive Jira ticket with all context for developer + JIRA_DESCRIPTION=$(cat < Date: Thu, 25 Jun 2026 15:58:10 -0700 Subject: [PATCH 02/21] Temp test --- ...ublish_image_autoinstrumentation_beta.yaml | 82 ++++++++++--------- image/requirements.txt | 4 +- solarwinds_apm/version.py | 2 +- 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index b419dc1de..7dc258457 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -56,16 +56,17 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push - amd64, arm64 - uses: docker/build-push-action@v7 - with: - push: true - context: image - file: image/Dockerfile-beta - platforms: linux/amd64,linux/arm64 - build-args: version=${{ env.VERSION }}-beta - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + # TEMP: Push disabled to test Jira ticket creation + # - name: Build and push - amd64, arm64 + # uses: docker/build-push-action@v7 + # with: + # push: true + # context: image + # file: image/Dockerfile-beta + # platforms: linux/amd64,linux/arm64 + # build-args: version=${{ env.VERSION }}-beta + # tags: ${{ steps.meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} - name: Build locally for scan - amd64 uses: docker/build-push-action@v7 @@ -168,33 +169,34 @@ jobs: done < vulnerabilities.json - ghcr_io: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - name: Read solarwinds_apm version requirement - run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Login to GitHub Package Registry - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v7 - with: - push: true - context: image - file: image/Dockerfile-beta - platforms: linux/amd64,linux/arm64 - build-args: version=${{ env.VERSION }}-beta - tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta + # TEMP: ghcr.io job disabled to test Jira ticket creation + # ghcr_io: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v7 + + # - name: Read solarwinds_apm version requirement + # run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV + + # - name: Set up QEMU + # uses: docker/setup-qemu-action@v4 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v4 + + # - name: Login to GitHub Package Registry + # uses: docker/login-action@v4 + # with: + # registry: ghcr.io + # username: ${{ github.actor }} + # password: ${{ secrets.GITHUB_TOKEN }} + + # - name: Build and push + # uses: docker/build-push-action@v7 + # with: + # push: true + # context: image + # file: image/Dockerfile-beta + # platforms: linux/amd64,linux/arm64 + # build-args: version=${{ env.VERSION }}-beta + # tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta diff --git a/image/requirements.txt b/image/requirements.txt index 610f1a5ea..36446b9e3 100644 --- a/image/requirements.txt +++ b/image/requirements.txt @@ -3,8 +3,8 @@ opentelemetry-api==1.42.1 opentelemetry-sdk==1.42.1 opentelemetry-instrumentation==0.63b1 -urllib3 >= 2.7.0, < 3.0.0 -requests >= 2.33.0, < 3.0 +# TEMP: force a vulnerability alert +urllib3 < 2.7.0 # We don't use the otlp_proto_grpc option since gRPC is not appropriate for # injected auto-instrumentation, where it has a strict dependency on the OS / Python version the artifact is built for. opentelemetry-exporter-otlp-proto-http==1.42.1 diff --git a/solarwinds_apm/version.py b/solarwinds_apm/version.py index b378fc6cc..89f1ba911 100644 --- a/solarwinds_apm/version.py +++ b/solarwinds_apm/version.py @@ -1 +1 @@ -__version__ = "7.0.0" +__version__ = "7.1.0.0" From f8189339952c848f44c03bb765f9b206b168cf78 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 10:21:03 -0700 Subject: [PATCH 03/21] Debug --- ...ublish_image_autoinstrumentation_beta.yaml | 129 +++++++++++++++--- 1 file changed, 111 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 7dc258457..156610cae 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -116,6 +116,28 @@ jobs: JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} run: | + set +e # Don't exit on error, handle errors explicitly + + # Validate secrets are set + if [ -z "$JIRA_BASE_URL" ] || [ -z "$JIRA_USER_EMAIL" ] || [ -z "$JIRA_API_TOKEN" ]; then + echo "❌ ERROR: Required Jira secrets are not set" + echo "JIRA_BASE_URL: ${JIRA_BASE_URL:+SET}" + echo "JIRA_USER_EMAIL: ${JIRA_USER_EMAIL:+SET}" + echo "JIRA_API_TOKEN: ${JIRA_API_TOKEN:+SET}" + exit 1 + fi + + # Test connectivity to Jira + echo "Testing connection to Jira at: ${JIRA_BASE_URL}" + HEALTH_CHECK=$(curl -s -w "\n%{http_code}" --max-time 10 "${JIRA_BASE_URL}/status" 2>&1) + HEALTH_CODE=$(echo "$HEALTH_CHECK" | tail -n1) + echo "Jira connectivity test returned: $HEALTH_CODE" + + echo "Processing ${{ steps.parse-cves.outputs.count }} vulnerabilities..." + + TICKET_COUNT=0 + ERROR_COUNT=0 + while IFS= read -r vuln; do CVE=$(echo "$vuln" | jq -r '.ruleId') PACKAGE=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.artifactLocation.uri // "unknown"') @@ -123,6 +145,11 @@ jobs: MESSAGE=$(echo "$vuln" | jq -r '.message.text') SEVERITY=$(echo "$vuln" | jq -r '.level') + echo "----------------------------------------" + echo "Processing CVE: ${CVE}" + echo "Package: ${PACKAGE}" + echo "Severity: ${SEVERITY}" + # Create comprehensive Jira ticket with all context for developer JIRA_DESCRIPTION=$(cat < Date: Fri, 26 Jun 2026 14:06:57 -0700 Subject: [PATCH 04/21] Create Description object and other type fixes --- ...ublish_image_autoinstrumentation_beta.yaml | 227 ++++++++++++++---- 1 file changed, 182 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 156610cae..6055f61f9 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -150,29 +150,188 @@ jobs: echo "Package: ${PACKAGE}" echo "Severity: ${SEVERITY}" - # Create comprehensive Jira ticket with all context for developer - JIRA_DESCRIPTION=$(cat < Date: Fri, 26 Jun 2026 14:14:29 -0700 Subject: [PATCH 05/21] jq instead of yaml parse --- ...ublish_image_autoinstrumentation_beta.yaml | 263 +++++++----------- 1 file changed, 93 insertions(+), 170 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 6055f61f9..e92f34f93 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -150,96 +150,7 @@ jobs: echo "Package: ${PACKAGE}" echo "Severity: ${SEVERITY}" - # Create Jira description in Atlassian Document Format (ADF) - # ADF is required for Jira API v3 descriptions - JIRA_DESCRIPTION=$(cat <<'EOF' -{ - "version": 1, - "type": "doc", - "content": [ - { - "type": "heading", - "attrs": {"level": 2}, - "content": [{"type": "text", "text": "Security Vulnerability Detected"}] - }, - { - "type": "paragraph", - "content": [ - {"type": "text", "text": "CVE: ", "marks": [{"type": "strong"}]}, - {"type": "text", "text": "CVE_PLACEHOLDER"} - ] - }, - { - "type": "paragraph", - "content": [ - {"type": "text", "text": "Package: ", "marks": [{"type": "strong"}]}, - {"type": "text", "text": "PACKAGE_PLACEHOLDER"} - ] - }, - { - "type": "paragraph", - "content": [ - {"type": "text", "text": "Version: ", "marks": [{"type": "strong"}]}, - {"type": "text", "text": "VERSION_PLACEHOLDER"} - ] - }, - { - "type": "paragraph", - "content": [ - {"type": "text", "text": "Severity: ", "marks": [{"type": "strong"}]}, - {"type": "text", "text": "SEVERITY_PLACEHOLDER"} - ] - }, - { - "type": "paragraph", - "content": [ - {"type": "text", "text": "Image: ", "marks": [{"type": "strong"}]}, - {"type": "text", "text": "IMAGE_PLACEHOLDER"} - ] - }, - { - "type": "heading", - "attrs": {"level": 3}, - "content": [{"type": "text", "text": "Description"}] - }, - { - "type": "paragraph", - "content": [{"type": "text", "text": "MESSAGE_PLACEHOLDER"}] - }, - { - "type": "heading", - "attrs": {"level": 3}, - "content": [{"type": "text", "text": "Recommended Action"}] - }, - { - "type": "paragraph", - "content": [{"type": "text", "text": "Upgrade the vulnerable dependency to the latest secure version."}] - }, - { - "type": "heading", - "attrs": {"level": 3}, - "content": [{"type": "text", "text": "Detection Source"}] - }, - { - "type": "paragraph", - "content": [ - {"type": "text", "text": "Workflow Run: ", "marks": [{"type": "strong"}]}, - {"type": "text", "text": "WORKFLOW_URL_PLACEHOLDER", "marks": [{"type": "link", "attrs": {"href": "WORKFLOW_URL_PLACEHOLDER"}}]} - ] - }, - { - "type": "paragraph", - "content": [ - {"type": "text", "text": "Commit: ", "marks": [{"type": "strong"}]}, - {"type": "text", "text": "COMMIT_PLACEHOLDER"} - ] - } - ] -} -EOF - ) - - # Replace placeholders with actual values and build complete request JSON + # Prepare values for Jira ticket SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" @@ -249,87 +160,99 @@ EOF VULN_COMPONENT="${PACKAGE}-${VERSION}" if [ -n "$TEAM_ID" ]; then - # Build with team field - JIRA_REQUEST=$(echo "$JIRA_DESCRIPTION" | \ - jq --arg cve "$CVE" \ - --arg pkg "$PACKAGE" \ - --arg ver "$VERSION" \ - --arg sev "$SEVERITY_TEXT" \ - --arg img "${{ steps.meta.outputs.tags[0] }}" \ - --arg msg "$MESSAGE" \ - --arg url "$WORKFLOW_URL" \ - --arg commit "${{ github.sha }}" \ - --arg summary "${CVE}: Python - ${PACKAGE}" \ - --arg teamId "$TEAM_ID" \ - --arg reportDate "$REPORT_DATE" \ - --arg vulnComponent "$VULN_COMPONENT" \ - '{ - fields: { - project: {key: "NH"}, - summary: $summary, - description: ( - . | - (.content[1].content[1].text = $cve) | - (.content[2].content[1].text = $pkg) | - (.content[3].content[1].text = $ver) | - (.content[4].content[1].text = $sev) | - (.content[5].content[1].text = $img) | - (.content[7].content[0].text = $msg) | - (.content[11].content[1].text = $url) | - (.content[11].content[1].marks[0].attrs.href = $url) | - (.content[12].content[1].text = $commit) - ), - issuetype: {name: "Security Vuln"}, - components: [{name: "Instrument Python"}], - customfield_10001: $teamId, - customfield_10369: $reportDate, - customfield_10374: "[" + $cve + "]", - customfield_10392: $vulnComponent, - labels: ["security", "cve", "docker-scout", "autoinstrumentation"], - priority: {name: "Critical"} - } - }' - ) + # Build with team field and ADF description + JIRA_REQUEST=$(jq -n \ + --arg cve "$CVE" \ + --arg pkg "$PACKAGE" \ + --arg ver "$VERSION" \ + --arg sev "$SEVERITY_TEXT" \ + --arg img "${{ steps.meta.outputs.tags[0] }}" \ + --arg msg "$MESSAGE" \ + --arg url "$WORKFLOW_URL" \ + --arg commit "${{ github.sha }}" \ + --arg summary "${CVE}: Python - ${PACKAGE}" \ + --arg teamId "$TEAM_ID" \ + --arg reportDate "$REPORT_DATE" \ + --arg vulnComponent "$VULN_COMPONENT" \ + '{ + fields: { + project: {key: "NH"}, + summary: $summary, + description: { + version: 1, + type: "doc", + content: [ + {type: "heading", attrs: {level: 2}, content: [{type: "text", text: "Security Vulnerability Detected"}]}, + {type: "paragraph", content: [{type: "text", text: "CVE: ", marks: [{type: "strong"}]}, {type: "text", text: $cve}]}, + {type: "paragraph", content: [{type: "text", text: "Package: ", marks: [{type: "strong"}]}, {type: "text", text: $pkg}]}, + {type: "paragraph", content: [{type: "text", text: "Version: ", marks: [{type: "strong"}]}, {type: "text", text: $ver}]}, + {type: "paragraph", content: [{type: "text", text: "Severity: ", marks: [{type: "strong"}]}, {type: "text", text: $sev}]}, + {type: "paragraph", content: [{type: "text", text: "Image: ", marks: [{type: "strong"}]}, {type: "text", text: $img}]}, + {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Description"}]}, + {type: "paragraph", content: [{type: "text", text: $msg}]}, + {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Recommended Action"}]}, + {type: "paragraph", content: [{type: "text", text: "Upgrade the vulnerable dependency to the latest secure version."}]}, + {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Detection Source"}]}, + {type: "paragraph", content: [{type: "text", text: "Workflow Run: ", marks: [{type: "strong"}]}, {type: "text", text: $url, marks: [{type: "link", attrs: {href: $url}}]}]}, + {type: "paragraph", content: [{type: "text", text: "Commit: ", marks: [{type: "strong"}]}, {type: "text", text: $commit}]} + ] + }, + issuetype: {name: "Security Vuln"}, + components: [{name: "Instrument Python"}], + customfield_10001: $teamId, + customfield_10369: $reportDate, + customfield_10374: ("[" + $cve + "]"), + customfield_10392: $vulnComponent, + labels: ["docker-scout"], + priority: {name: "Critical"} + } + }') else - # Build without team field - JIRA_REQUEST=$(echo "$JIRA_DESCRIPTION" | \ - jq --arg cve "$CVE" \ - --arg pkg "$PACKAGE" \ - --arg ver "$VERSION" \ - --arg sev "$SEVERITY_TEXT" \ - --arg img "${{ steps.meta.outputs.tags[0] }}" \ - --arg msg "$MESSAGE" \ - --arg url "$WORKFLOW_URL" \ - --arg commit "${{ github.sha }}" \ - --arg summary "${CVE}: Python - ${PACKAGE}" \ - --arg reportDate "$REPORT_DATE" \ - --arg vulnComponent "$VULN_COMPONENT" \ - '{ - fields: { - project: {key: "NH"}, - summary: $summary, - description: ( - . | - (.content[1].content[1].text = $cve) | - (.content[2].content[1].text = $pkg) | - (.content[3].content[1].text = $ver) | - (.content[4].content[1].text = $sev) | - (.content[5].content[1].text = $img) | - (.content[7].content[0].text = $msg) | - (.content[11].content[1].text = $url) | - (.content[11].content[1].marks[0].attrs.href = $url) | - (.content[12].content[1].text = $commit) - ), - issuetype: {name: "Security Vuln"}, - components: [{name: "Instrument Python"}], - customfield_10369: $reportDate, - customfield_10374: "[" + $cve + "]", - customfield_10392: $vulnComponent, - labels: ["docker-scout"], - priority: {name: "Critical"} - } - }' - ) + # Build without team field and ADF description + JIRA_REQUEST=$(jq -n \ + --arg cve "$CVE" \ + --arg pkg "$PACKAGE" \ + --arg ver "$VERSION" \ + --arg sev "$SEVERITY_TEXT" \ + --arg img "${{ steps.meta.outputs.tags[0] }}" \ + --arg msg "$MESSAGE" \ + --arg url "$WORKFLOW_URL" \ + --arg commit "${{ github.sha }}" \ + --arg summary "${CVE}: Python - ${PACKAGE}" \ + --arg reportDate "$REPORT_DATE" \ + --arg vulnComponent "$VULN_COMPONENT" \ + '{ + fields: { + project: {key: "NH"}, + summary: $summary, + description: { + version: 1, + type: "doc", + content: [ + {type: "heading", attrs: {level: 2}, content: [{type: "text", text: "Security Vulnerability Detected"}]}, + {type: "paragraph", content: [{type: "text", text: "CVE: ", marks: [{type: "strong"}]}, {type: "text", text: $cve}]}, + {type: "paragraph", content: [{type: "text", text: "Package: ", marks: [{type: "strong"}]}, {type: "text", text: $pkg}]}, + {type: "paragraph", content: [{type: "text", text: "Version: ", marks: [{type: "strong"}]}, {type: "text", text: $ver}]}, + {type: "paragraph", content: [{type: "text", text: "Severity: ", marks: [{type: "strong"}]}, {type: "text", text: $sev}]}, + {type: "paragraph", content: [{type: "text", text: "Image: ", marks: [{type: "strong"}]}, {type: "text", text: $img}]}, + {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Description"}]}, + {type: "paragraph", content: [{type: "text", text: $msg}]}, + {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Recommended Action"}]}, + {type: "paragraph", content: [{type: "text", text: "Upgrade the vulnerable dependency to the latest secure version."}]}, + {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Detection Source"}]}, + {type: "paragraph", content: [{type: "text", text: "Workflow Run: ", marks: [{type: "strong"}]}, {type: "text", text: $url, marks: [{type: "link", attrs: {href: $url}}]}]}, + {type: "paragraph", content: [{type: "text", text: "Commit: ", marks: [{type: "strong"}]}, {type: "text", text: $commit}]} + ] + }, + issuetype: {name: "Security Vuln"}, + components: [{name: "Instrument Python"}], + customfield_10369: $reportDate, + customfield_10374: ("[" + $cve + "]"), + customfield_10392: $vulnComponent, + labels: ["docker-scout"], + priority: {name: "Critical"} + } + }') fi # Attempt Jira API call with additional debugging for first request only From 619ca2698f1eba1a3403853c29a9d0567e00b83d Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 14:24:41 -0700 Subject: [PATCH 06/21] More debug --- ...ublish_image_autoinstrumentation_beta.yaml | 79 ++++++++++++++----- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index e92f34f93..56e8cc8ae 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -255,47 +255,86 @@ jobs: }') fi + # Validate JSON payload before sending + if ! echo "$JIRA_REQUEST" | jq empty 2>/dev/null; then + echo "❌ ERROR: Generated invalid JSON payload" + echo "First 500 chars of payload:" + echo "$JIRA_REQUEST" | head -c 500 + ((ERROR_COUNT++)) + continue + fi + + # Show payload size and preview for first request + if [ $TICKET_COUNT -eq 0 ] && [ $ERROR_COUNT -eq 0 ]; then + PAYLOAD_SIZE=$(echo "$JIRA_REQUEST" | wc -c) + echo "Payload size: ${PAYLOAD_SIZE} bytes" + echo "Payload preview (first 300 chars):" + echo "$JIRA_REQUEST" | head -c 300 + echo "..." + echo "" + + # Test base64 encoding + TEST_BASE64=$(echo -n "test@example.com:token123" | base64) + echo "Base64 encoding test successful: ${#TEST_BASE64} chars" + fi + # Attempt Jira API call with additional debugging for first request only if [ $TICKET_COUNT -eq 0 ] && [ $ERROR_COUNT -eq 0 ]; then echo "First request - showing connection details (auth headers masked)..." echo "POST ${JIRA_BASE_URL}/rest/api/3/issue" echo "Authorization: Basic ****MASKED****" echo "Content-Type: application/json" + echo "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" - # Show payload structure (not full content to keep logs clean) - echo "Payload fields: project, summary, description, issuetype, components, customfield_10001, labels, priority" + # Use temp file for response body to avoid mixing with verbose output + TEMP_RESPONSE=$(mktemp) - # Use write-out to get connection timing info (safe - no sensitive data) - JIRA_RESPONSE=$(curl -s -w "\ntime_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_starttransfer:%{time_starttransfer}\nhttp_code:%{http_code}" \ - --connect-timeout 30 --max-time 60 \ + # Use write-out to get connection timing and detailed diagnostics + JIRA_METRICS=$(curl -v -w "\ntime_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_appconnect:%{time_appconnect}\ntime_pretransfer:%{time_pretransfer}\ntime_starttransfer:%{time_starttransfer}\ntime_total:%{time_total}\nhttp_code:%{http_code}\nsize_upload:%{size_upload}" \ + --connect-timeout 30 --max-time 90 \ + -o "$TEMP_RESPONSE" \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ -H "Content-Type: application/json" \ - -d "$JIRA_REQUEST") + -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ + -d "$JIRA_REQUEST" 2>&1) + + # Extract timing info from metrics + echo "DNS lookup time: $(echo "$JIRA_METRICS" | grep time_namelookup | cut -d: -f2)" + echo "Connect time: $(echo "$JIRA_METRICS" | grep time_connect | cut -d: -f2)" + echo "SSL handshake time: $(echo "$JIRA_METRICS" | grep time_appconnect | cut -d: -f2)" + echo "Pre-transfer time: $(echo "$JIRA_METRICS" | grep time_pretransfer | cut -d: -f2)" + echo "Time to first byte: $(echo "$JIRA_METRICS" | grep time_starttransfer | cut -d: -f2)" + echo "Total time: $(echo "$JIRA_METRICS" | grep time_total | cut -d: -f2)" + echo "Bytes uploaded: $(echo "$JIRA_METRICS" | grep size_upload | cut -d: -f2)" - # Extract and display timing info - echo "DNS lookup time: $(echo "$JIRA_RESPONSE" | grep time_namelookup | cut -d: -f2)" - echo "Connect time: $(echo "$JIRA_RESPONSE" | grep time_connect | cut -d: -f2)" - echo "Time to first byte: $(echo "$JIRA_RESPONSE" | grep time_starttransfer | cut -d: -f2)" + # Get HTTP code and response body + HTTP_CODE=$(echo "$JIRA_METRICS" | grep http_code | cut -d: -f2 | tr -d ' ') + RESPONSE_BODY=$(cat "$TEMP_RESPONSE") + rm -f "$TEMP_RESPONSE" + + # Show curl diagnostics if HTTP 000 + if [ "$HTTP_CODE" = "000" ]; then + echo "⚠️ HTTP 000 error - showing curl diagnostics:" + echo "$JIRA_METRICS" | head -n 100 + fi else - JIRA_RESPONSE=$(curl -s -w "\n%{http_code}" --connect-timeout 30 --max-time 60 \ + JIRA_RESPONSE=$(curl -s -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ -H "Content-Type: application/json" \ + -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ -d "$JIRA_REQUEST") - fi - - # Parse response - first response has timing info, others are simple - if [ $TICKET_COUNT -eq 0 ] && [ $ERROR_COUNT -eq 0 ]; then - HTTP_CODE=$(echo "$JIRA_RESPONSE" | grep http_code | cut -d: -f2) - # Get response body (everything before timing info lines) - RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '/time_namelookup:/,$d') - else + HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') fi - if [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then + # Process response (HTTP_CODE and RESPONSE_BODY already set above) + if [ "$HTTP_CODE" = "000" ]; then + echo "❌ Connection error (curl returned 000) - check curl diagnostics above" + ((ERROR_COUNT++)) + elif [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then JIRA_KEY=$(echo "$RESPONSE_BODY" | jq -r '.key // "null"') if [ "$JIRA_KEY" != "null" ] && [ -n "$JIRA_KEY" ]; then JIRA_URL="${JIRA_BASE_URL}/browse/${JIRA_KEY}" From 2c58ae0de39e9531ea22ebe56ae2b089b366e7b9 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 14:32:15 -0700 Subject: [PATCH 07/21] Change to temp file approach --- ...ld_publish_image_autoinstrumentation_beta.yaml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 56e8cc8ae..6c96f9bc7 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -286,8 +286,10 @@ jobs: echo "Content-Type: application/json" echo "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" - # Use temp file for response body to avoid mixing with verbose output + # Use temp files for both request and response + TEMP_REQUEST=$(mktemp) TEMP_RESPONSE=$(mktemp) + echo "$JIRA_REQUEST" > "$TEMP_REQUEST" # Use write-out to get connection timing and detailed diagnostics JIRA_METRICS=$(curl -v -w "\ntime_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_appconnect:%{time_appconnect}\ntime_pretransfer:%{time_pretransfer}\ntime_starttransfer:%{time_starttransfer}\ntime_total:%{time_total}\nhttp_code:%{http_code}\nsize_upload:%{size_upload}" \ @@ -297,7 +299,7 @@ jobs: -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ -H "Content-Type: application/json" \ -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ - -d "$JIRA_REQUEST" 2>&1) + -d @"$TEMP_REQUEST" 2>&1) # Extract timing info from metrics echo "DNS lookup time: $(echo "$JIRA_METRICS" | grep time_namelookup | cut -d: -f2)" @@ -311,7 +313,7 @@ jobs: # Get HTTP code and response body HTTP_CODE=$(echo "$JIRA_METRICS" | grep http_code | cut -d: -f2 | tr -d ' ') RESPONSE_BODY=$(cat "$TEMP_RESPONSE") - rm -f "$TEMP_RESPONSE" + rm -f "$TEMP_REQUEST" "$TEMP_RESPONSE" # Show curl diagnostics if HTTP 000 if [ "$HTTP_CODE" = "000" ]; then @@ -319,15 +321,20 @@ jobs: echo "$JIRA_METRICS" | head -n 100 fi else + # Use temp file for request body (subsequent requests) + TEMP_REQUEST=$(mktemp) + echo "$JIRA_REQUEST" > "$TEMP_REQUEST" + JIRA_RESPONSE=$(curl -s -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ -H "Content-Type: application/json" \ -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ - -d "$JIRA_REQUEST") + -d @"$TEMP_REQUEST") HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') + rm -f "$TEMP_REQUEST" fi # Process response (HTTP_CODE and RESPONSE_BODY already set above) From cdb49ffa9267ffa8a7b72a5fe8e47bcbd6fa5585 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 14:40:54 -0700 Subject: [PATCH 08/21] Use http1.1 --- .../build_publish_image_autoinstrumentation_beta.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 6c96f9bc7..669100eca 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -292,7 +292,8 @@ jobs: echo "$JIRA_REQUEST" > "$TEMP_REQUEST" # Use write-out to get connection timing and detailed diagnostics - JIRA_METRICS=$(curl -v -w "\ntime_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_appconnect:%{time_appconnect}\ntime_pretransfer:%{time_pretransfer}\ntime_starttransfer:%{time_starttransfer}\ntime_total:%{time_total}\nhttp_code:%{http_code}\nsize_upload:%{size_upload}" \ + # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues + JIRA_METRICS=$(curl -v --http1.1 -w "\ntime_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_appconnect:%{time_appconnect}\ntime_pretransfer:%{time_pretransfer}\ntime_starttransfer:%{time_starttransfer}\ntime_total:%{time_total}\nhttp_code:%{http_code}\nsize_upload:%{size_upload}" \ --connect-timeout 30 --max-time 90 \ -o "$TEMP_RESPONSE" \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ @@ -322,10 +323,11 @@ jobs: fi else # Use temp file for request body (subsequent requests) + # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues TEMP_REQUEST=$(mktemp) echo "$JIRA_REQUEST" > "$TEMP_REQUEST" - JIRA_RESPONSE=$(curl -s -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ + JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ -H "Content-Type: application/json" \ From 280271752b6339634a94669604794258b9990cc7 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 15:00:55 -0700 Subject: [PATCH 09/21] --data-binary --- .../build_publish_image_autoinstrumentation_beta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 669100eca..fb566173d 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -300,7 +300,7 @@ jobs: -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ -H "Content-Type: application/json" \ -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ - -d @"$TEMP_REQUEST" 2>&1) + --data-binary @"$TEMP_REQUEST" 2>&1) # Extract timing info from metrics echo "DNS lookup time: $(echo "$JIRA_METRICS" | grep time_namelookup | cut -d: -f2)" @@ -332,7 +332,7 @@ jobs: -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ -H "Content-Type: application/json" \ -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ - -d @"$TEMP_REQUEST") + --data-binary @"$TEMP_REQUEST") HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') From b85e3150fd2bff9a6e3f3c267e976f6e7fc86f2f Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 15:10:45 -0700 Subject: [PATCH 10/21] debug --- .../build_publish_image_autoinstrumentation_beta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index fb566173d..7d9294cb8 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -289,7 +289,7 @@ jobs: # Use temp files for both request and response TEMP_REQUEST=$(mktemp) TEMP_RESPONSE=$(mktemp) - echo "$JIRA_REQUEST" > "$TEMP_REQUEST" + printf '%s' "$JIRA_REQUEST" > "$TEMP_REQUEST" # Use write-out to get connection timing and detailed diagnostics # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues @@ -325,7 +325,7 @@ jobs: # Use temp file for request body (subsequent requests) # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues TEMP_REQUEST=$(mktemp) - echo "$JIRA_REQUEST" > "$TEMP_REQUEST" + printf '%s' "$JIRA_REQUEST" > "$TEMP_REQUEST" JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ From af88f23153dce13a33899dc48832eb735a10c2f1 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 15:17:55 -0700 Subject: [PATCH 11/21] Add sanitation, more debug --- ...ublish_image_autoinstrumentation_beta.yaml | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 7d9294cb8..7ff6a76e1 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -142,14 +142,24 @@ jobs: CVE=$(echo "$vuln" | jq -r '.ruleId') PACKAGE=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.artifactLocation.uri // "unknown"') VERSION=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.region.snippet.text // "unknown"') - MESSAGE=$(echo "$vuln" | jq -r '.message.text') + RAW_MESSAGE=$(echo "$vuln" | jq -r '.message.text') SEVERITY=$(echo "$vuln" | jq -r '.level') + # Sanitize MESSAGE: remove control characters but keep newlines/tabs + MESSAGE=$(echo "$RAW_MESSAGE" | tr -d '\000-\010\013\014\016-\037') + echo "----------------------------------------" echo "Processing CVE: ${CVE}" echo "Package: ${PACKAGE}" echo "Severity: ${SEVERITY}" + # Check if sanitization removed characters + RAW_LEN=${#RAW_MESSAGE} + CLEAN_LEN=${#MESSAGE} + if [ "$RAW_LEN" -ne "$CLEAN_LEN" ]; then + echo "⚠️ Sanitized message: removed $((RAW_LEN - CLEAN_LEN)) control characters" + fi + # Prepare values for Jira ticket SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" @@ -273,6 +283,16 @@ jobs: echo "..." echo "" + # Check for non-printable characters + NON_PRINTABLE=$(echo "$JIRA_REQUEST" | tr -d '[:print:]\n\t' | wc -c) + if [ "$NON_PRINTABLE" -gt 0 ]; then + echo "⚠️ WARNING: Payload contains $NON_PRINTABLE non-printable characters" + echo "First 100 bytes in hex:" + echo "$JIRA_REQUEST" | head -c 100 | xxd | head -5 + else + echo "✅ Payload contains only printable characters" + fi + # Test base64 encoding TEST_BASE64=$(echo -n "test@example.com:token123" | base64) echo "Base64 encoding test successful: ${#TEST_BASE64} chars" @@ -289,16 +309,18 @@ jobs: # Use temp files for both request and response TEMP_REQUEST=$(mktemp) TEMP_RESPONSE=$(mktemp) - printf '%s' "$JIRA_REQUEST" > "$TEMP_REQUEST" + printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" # Use write-out to get connection timing and detailed diagnostics # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues + # Use -u for auth to avoid base64 encoding issues JIRA_METRICS=$(curl -v --http1.1 -w "\ntime_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_appconnect:%{time_appconnect}\ntime_pretransfer:%{time_pretransfer}\ntime_starttransfer:%{time_starttransfer}\ntime_total:%{time_total}\nhttp_code:%{http_code}\nsize_upload:%{size_upload}" \ --connect-timeout 30 --max-time 90 \ -o "$TEMP_RESPONSE" \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ - -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ - -H "Content-Type: application/json" \ + -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Accept: application/json" \ -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ --data-binary @"$TEMP_REQUEST" 2>&1) @@ -325,12 +347,13 @@ jobs: # Use temp file for request body (subsequent requests) # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues TEMP_REQUEST=$(mktemp) - printf '%s' "$JIRA_REQUEST" > "$TEMP_REQUEST" + printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ - -H "Authorization: Basic $(echo -n ${JIRA_USER_EMAIL}:${JIRA_API_TOKEN} | base64)" \ - -H "Content-Type: application/json" \ + -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Accept: application/json" \ -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ --data-binary @"$TEMP_REQUEST") From f5d4a4328e2fd3ffb1f9593d070da1cf3f2d34df Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 15:53:03 -0700 Subject: [PATCH 12/21] Trim down logging --- ...ublish_image_autoinstrumentation_beta.yaml | 173 +++--------------- 1 file changed, 30 insertions(+), 143 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 7ff6a76e1..798c2d386 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -116,27 +116,11 @@ jobs: JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} run: | - set +e # Don't exit on error, handle errors explicitly - - # Validate secrets are set - if [ -z "$JIRA_BASE_URL" ] || [ -z "$JIRA_USER_EMAIL" ] || [ -z "$JIRA_API_TOKEN" ]; then - echo "❌ ERROR: Required Jira secrets are not set" - echo "JIRA_BASE_URL: ${JIRA_BASE_URL:+SET}" - echo "JIRA_USER_EMAIL: ${JIRA_USER_EMAIL:+SET}" - echo "JIRA_API_TOKEN: ${JIRA_API_TOKEN:+SET}" - exit 1 - fi - - # Test connectivity to Jira - echo "Testing connection to Jira at: ${JIRA_BASE_URL}" - HEALTH_CHECK=$(curl -s -w "\n%{http_code}" --max-time 10 "${JIRA_BASE_URL}/status" 2>&1) - HEALTH_CODE=$(echo "$HEALTH_CHECK" | tail -n1) - echo "Jira connectivity test returned: $HEALTH_CODE" - - echo "Processing ${{ steps.parse-cves.outputs.count }} vulnerabilities..." - + set +e + TICKET_COUNT=0 ERROR_COUNT=0 + CREATED_TICKETS=() while IFS= read -r vuln; do CVE=$(echo "$vuln" | jq -r '.ruleId') @@ -148,29 +132,15 @@ jobs: # Sanitize MESSAGE: remove control characters but keep newlines/tabs MESSAGE=$(echo "$RAW_MESSAGE" | tr -d '\000-\010\013\014\016-\037') - echo "----------------------------------------" - echo "Processing CVE: ${CVE}" - echo "Package: ${PACKAGE}" - echo "Severity: ${SEVERITY}" - - # Check if sanitization removed characters - RAW_LEN=${#RAW_MESSAGE} - CLEAN_LEN=${#MESSAGE} - if [ "$RAW_LEN" -ne "$CLEAN_LEN" ]; then - echo "⚠️ Sanitized message: removed $((RAW_LEN - CLEAN_LEN)) control characters" - fi - - # Prepare values for Jira ticket + echo "Processing ${CVE}..." SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - # Build complete Jira request with ADF description using jq + + # Build request with ADF description using jq; cannot be plain string TEAM_ID="${{ secrets.JIRA_TEAM_FIELD_ID }}" REPORT_DATE=$(date +%Y-%m-%d) VULN_COMPONENT="${PACKAGE}-${VERSION}" - if [ -n "$TEAM_ID" ]; then - # Build with team field and ADF description JIRA_REQUEST=$(jq -n \ --arg cve "$CVE" \ --arg pkg "$PACKAGE" \ @@ -264,132 +234,49 @@ jobs: } }') fi + + + TEMP_REQUEST=$(mktemp) + printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" - # Validate JSON payload before sending - if ! echo "$JIRA_REQUEST" | jq empty 2>/dev/null; then - echo "❌ ERROR: Generated invalid JSON payload" - echo "First 500 chars of payload:" - echo "$JIRA_REQUEST" | head -c 500 - ((ERROR_COUNT++)) - continue - fi - - # Show payload size and preview for first request - if [ $TICKET_COUNT -eq 0 ] && [ $ERROR_COUNT -eq 0 ]; then - PAYLOAD_SIZE=$(echo "$JIRA_REQUEST" | wc -c) - echo "Payload size: ${PAYLOAD_SIZE} bytes" - echo "Payload preview (first 300 chars):" - echo "$JIRA_REQUEST" | head -c 300 - echo "..." - echo "" - - # Check for non-printable characters - NON_PRINTABLE=$(echo "$JIRA_REQUEST" | tr -d '[:print:]\n\t' | wc -c) - if [ "$NON_PRINTABLE" -gt 0 ]; then - echo "⚠️ WARNING: Payload contains $NON_PRINTABLE non-printable characters" - echo "First 100 bytes in hex:" - echo "$JIRA_REQUEST" | head -c 100 | xxd | head -5 - else - echo "✅ Payload contains only printable characters" - fi - - # Test base64 encoding - TEST_BASE64=$(echo -n "test@example.com:token123" | base64) - echo "Base64 encoding test successful: ${#TEST_BASE64} chars" - fi + JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ + -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ + -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Accept: application/json" \ + --data-binary @"$TEMP_REQUEST") - # Attempt Jira API call with additional debugging for first request only - if [ $TICKET_COUNT -eq 0 ] && [ $ERROR_COUNT -eq 0 ]; then - echo "First request - showing connection details (auth headers masked)..." - echo "POST ${JIRA_BASE_URL}/rest/api/3/issue" - echo "Authorization: Basic ****MASKED****" - echo "Content-Type: application/json" - echo "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" - - # Use temp files for both request and response - TEMP_REQUEST=$(mktemp) - TEMP_RESPONSE=$(mktemp) - printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" - - # Use write-out to get connection timing and detailed diagnostics - # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues - # Use -u for auth to avoid base64 encoding issues - JIRA_METRICS=$(curl -v --http1.1 -w "\ntime_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_appconnect:%{time_appconnect}\ntime_pretransfer:%{time_pretransfer}\ntime_starttransfer:%{time_starttransfer}\ntime_total:%{time_total}\nhttp_code:%{http_code}\nsize_upload:%{size_upload}" \ - --connect-timeout 30 --max-time 90 \ - -o "$TEMP_RESPONSE" \ - -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ - -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ - -H "Content-Type: application/json; charset=utf-8" \ - -H "Accept: application/json" \ - -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ - --data-binary @"$TEMP_REQUEST" 2>&1) - - # Extract timing info from metrics - echo "DNS lookup time: $(echo "$JIRA_METRICS" | grep time_namelookup | cut -d: -f2)" - echo "Connect time: $(echo "$JIRA_METRICS" | grep time_connect | cut -d: -f2)" - echo "SSL handshake time: $(echo "$JIRA_METRICS" | grep time_appconnect | cut -d: -f2)" - echo "Pre-transfer time: $(echo "$JIRA_METRICS" | grep time_pretransfer | cut -d: -f2)" - echo "Time to first byte: $(echo "$JIRA_METRICS" | grep time_starttransfer | cut -d: -f2)" - echo "Total time: $(echo "$JIRA_METRICS" | grep time_total | cut -d: -f2)" - echo "Bytes uploaded: $(echo "$JIRA_METRICS" | grep size_upload | cut -d: -f2)" - - # Get HTTP code and response body - HTTP_CODE=$(echo "$JIRA_METRICS" | grep http_code | cut -d: -f2 | tr -d ' ') - RESPONSE_BODY=$(cat "$TEMP_RESPONSE") - rm -f "$TEMP_REQUEST" "$TEMP_RESPONSE" - - # Show curl diagnostics if HTTP 000 - if [ "$HTTP_CODE" = "000" ]; then - echo "⚠️ HTTP 000 error - showing curl diagnostics:" - echo "$JIRA_METRICS" | head -n 100 - fi - else - # Use temp file for request body (subsequent requests) - # Force HTTP/1.1 to avoid HTTP/2 POST body upload issues - TEMP_REQUEST=$(mktemp) - printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" - - JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ - -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ - -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ - -H "Content-Type: application/json; charset=utf-8" \ - -H "Accept: application/json" \ - -H "User-Agent: GitHub-Actions-Docker-Scout-CVE-Reporter/1.0" \ - --data-binary @"$TEMP_REQUEST") - - HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) - RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') - rm -f "$TEMP_REQUEST" - fi + HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) + RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') + rm -f "$TEMP_REQUEST" - # Process response (HTTP_CODE and RESPONSE_BODY already set above) - if [ "$HTTP_CODE" = "000" ]; then - echo "❌ Connection error (curl returned 000) - check curl diagnostics above" - ((ERROR_COUNT++)) - elif [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then + # Process response + if [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then JIRA_KEY=$(echo "$RESPONSE_BODY" | jq -r '.key // "null"') if [ "$JIRA_KEY" != "null" ] && [ -n "$JIRA_KEY" ]; then JIRA_URL="${JIRA_BASE_URL}/browse/${JIRA_KEY}" - echo "✅ Created Jira ticket ${JIRA_KEY}: ${JIRA_URL}" + echo "✅ Created ${JIRA_KEY}: ${JIRA_URL}" + CREATED_TICKETS+=("$JIRA_KEY") ((TICKET_COUNT++)) else - echo "❌ Failed to parse Jira key from response" - echo "Response: $RESPONSE_BODY" + echo "❌ ${CVE}: Failed to parse ticket ID (HTTP ${HTTP_CODE})" ((ERROR_COUNT++)) fi else - echo "❌ Jira API returned HTTP $HTTP_CODE" - echo "Response: $RESPONSE_BODY" + echo "❌ ${CVE}: HTTP ${HTTP_CODE}" ((ERROR_COUNT++)) fi done < vulnerabilities.json echo "=========================================" - echo "Summary: Created $TICKET_COUNT tickets, $ERROR_COUNT errors" + if [ $TICKET_COUNT -gt 0 ]; then + TICKET_LIST=$(IFS=', '; echo "${CREATED_TICKETS[*]}") + echo "✅ Created ${TICKET_COUNT} tickets: ${TICKET_LIST}" + fi if [ $ERROR_COUNT -gt 0 ]; then - echo "⚠️ Some tickets failed to create. Check logs above." + echo "❌ Failed to create ${ERROR_COUNT} tickets" exit 1 fi From 0d90253c3efef334173b0430e32c8b7508c32dcd Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 16:04:29 -0700 Subject: [PATCH 13/21] Jira from template --- .github/templates/jira-security-vuln.json | 104 ++++++++++++++ ...ublish_image_autoinstrumentation_beta.yaml | 130 +++++------------- 2 files changed, 138 insertions(+), 96 deletions(-) create mode 100644 .github/templates/jira-security-vuln.json diff --git a/.github/templates/jira-security-vuln.json b/.github/templates/jira-security-vuln.json new file mode 100644 index 000000000..1a0bf5ad9 --- /dev/null +++ b/.github/templates/jira-security-vuln.json @@ -0,0 +1,104 @@ +{ + "fields": { + "project": { + "key": "NH" + }, + "summary": "$SUMMARY", + "description": { + "version": 1, + "type": "doc", + "content": [ + { + "type": "heading", + "attrs": {"level": 2}, + "content": [{"type": "text", "text": "Security Vulnerability Detected"}] + }, + { + "type": "paragraph", + "content": [ + {"type": "text", "text": "CVE: ", "marks": [{"type": "strong"}]}, + {"type": "text", "text": "$CVE"} + ] + }, + { + "type": "paragraph", + "content": [ + {"type": "text", "text": "Package: ", "marks": [{"type": "strong"}]}, + {"type": "text", "text": "$PACKAGE"} + ] + }, + { + "type": "paragraph", + "content": [ + {"type": "text", "text": "Version: ", "marks": [{"type": "strong"}]}, + {"type": "text", "text": "$VERSION"} + ] + }, + { + "type": "paragraph", + "content": [ + {"type": "text", "text": "Severity: ", "marks": [{"type": "strong"}]}, + {"type": "text", "text": "$SEVERITY"} + ] + }, + { + "type": "paragraph", + "content": [ + {"type": "text", "text": "Image: ", "marks": [{"type": "strong"}]}, + {"type": "text", "text": "$IMAGE"} + ] + }, + { + "type": "heading", + "attrs": {"level": 3}, + "content": [{"type": "text", "text": "Description"}] + }, + { + "type": "paragraph", + "content": [{"type": "text", "text": "$MESSAGE"}] + }, + { + "type": "heading", + "attrs": {"level": 3}, + "content": [{"type": "text", "text": "Recommended Action"}] + }, + { + "type": "paragraph", + "content": [{"type": "text", "text": "Upgrade the vulnerable dependency to the latest secure version."}] + }, + { + "type": "heading", + "attrs": {"level": 3}, + "content": [{"type": "text", "text": "Detection Source"}] + }, + { + "type": "paragraph", + "content": [ + {"type": "text", "text": "Workflow Run: ", "marks": [{"type": "strong"}]}, + {"type": "text", "text": "$WORKFLOW_URL", "marks": [{"type": "link", "attrs": {"href": "$WORKFLOW_URL"}}]} + ] + }, + { + "type": "paragraph", + "content": [ + {"type": "text", "text": "Commit: ", "marks": [{"type": "strong"}]}, + {"type": "text", "text": "$COMMIT"} + ] + } + ] + }, + "issuetype": { + "name": "Security Vuln" + }, + "components": [ + {"name": "Instrument Python"} + ], + "customfield_10369": "$REPORT_DATE", + "customfield_10374": "$CVE_ARRAY", + "customfield_10392": "$VULN_COMPONENT", + "labels": ["docker-scout"], + "priority": { + "name": "Critical" + } + } +} diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 798c2d386..cfb548087 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -135,106 +135,44 @@ jobs: echo "Processing ${CVE}..." SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - # Build request with ADF description using jq; cannot be plain string TEAM_ID="${{ secrets.JIRA_TEAM_FIELD_ID }}" REPORT_DATE=$(date +%Y-%m-%d) VULN_COMPONENT="${PACKAGE}-${VERSION}" - if [ -n "$TEAM_ID" ]; then - JIRA_REQUEST=$(jq -n \ - --arg cve "$CVE" \ - --arg pkg "$PACKAGE" \ - --arg ver "$VERSION" \ - --arg sev "$SEVERITY_TEXT" \ - --arg img "${{ steps.meta.outputs.tags[0] }}" \ - --arg msg "$MESSAGE" \ - --arg url "$WORKFLOW_URL" \ - --arg commit "${{ github.sha }}" \ - --arg summary "${CVE}: Python - ${PACKAGE}" \ - --arg teamId "$TEAM_ID" \ - --arg reportDate "$REPORT_DATE" \ - --arg vulnComponent "$VULN_COMPONENT" \ - '{ - fields: { - project: {key: "NH"}, - summary: $summary, - description: { - version: 1, - type: "doc", - content: [ - {type: "heading", attrs: {level: 2}, content: [{type: "text", text: "Security Vulnerability Detected"}]}, - {type: "paragraph", content: [{type: "text", text: "CVE: ", marks: [{type: "strong"}]}, {type: "text", text: $cve}]}, - {type: "paragraph", content: [{type: "text", text: "Package: ", marks: [{type: "strong"}]}, {type: "text", text: $pkg}]}, - {type: "paragraph", content: [{type: "text", text: "Version: ", marks: [{type: "strong"}]}, {type: "text", text: $ver}]}, - {type: "paragraph", content: [{type: "text", text: "Severity: ", marks: [{type: "strong"}]}, {type: "text", text: $sev}]}, - {type: "paragraph", content: [{type: "text", text: "Image: ", marks: [{type: "strong"}]}, {type: "text", text: $img}]}, - {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Description"}]}, - {type: "paragraph", content: [{type: "text", text: $msg}]}, - {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Recommended Action"}]}, - {type: "paragraph", content: [{type: "text", text: "Upgrade the vulnerable dependency to the latest secure version."}]}, - {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Detection Source"}]}, - {type: "paragraph", content: [{type: "text", text: "Workflow Run: ", marks: [{type: "strong"}]}, {type: "text", text: $url, marks: [{type: "link", attrs: {href: $url}}]}]}, - {type: "paragraph", content: [{type: "text", text: "Commit: ", marks: [{type: "strong"}]}, {type: "text", text: $commit}]} - ] - }, - issuetype: {name: "Security Vuln"}, - components: [{name: "Instrument Python"}], - customfield_10001: $teamId, - customfield_10369: $reportDate, - customfield_10374: ("[" + $cve + "]"), - customfield_10392: $vulnComponent, - labels: ["docker-scout"], - priority: {name: "Critical"} - } - }') - else - # Build without team field and ADF description - JIRA_REQUEST=$(jq -n \ - --arg cve "$CVE" \ - --arg pkg "$PACKAGE" \ - --arg ver "$VERSION" \ - --arg sev "$SEVERITY_TEXT" \ - --arg img "${{ steps.meta.outputs.tags[0] }}" \ - --arg msg "$MESSAGE" \ - --arg url "$WORKFLOW_URL" \ - --arg commit "${{ github.sha }}" \ - --arg summary "${CVE}: Python - ${PACKAGE}" \ - --arg reportDate "$REPORT_DATE" \ - --arg vulnComponent "$VULN_COMPONENT" \ - '{ - fields: { - project: {key: "NH"}, - summary: $summary, - description: { - version: 1, - type: "doc", - content: [ - {type: "heading", attrs: {level: 2}, content: [{type: "text", text: "Security Vulnerability Detected"}]}, - {type: "paragraph", content: [{type: "text", text: "CVE: ", marks: [{type: "strong"}]}, {type: "text", text: $cve}]}, - {type: "paragraph", content: [{type: "text", text: "Package: ", marks: [{type: "strong"}]}, {type: "text", text: $pkg}]}, - {type: "paragraph", content: [{type: "text", text: "Version: ", marks: [{type: "strong"}]}, {type: "text", text: $ver}]}, - {type: "paragraph", content: [{type: "text", text: "Severity: ", marks: [{type: "strong"}]}, {type: "text", text: $sev}]}, - {type: "paragraph", content: [{type: "text", text: "Image: ", marks: [{type: "strong"}]}, {type: "text", text: $img}]}, - {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Description"}]}, - {type: "paragraph", content: [{type: "text", text: $msg}]}, - {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Recommended Action"}]}, - {type: "paragraph", content: [{type: "text", text: "Upgrade the vulnerable dependency to the latest secure version."}]}, - {type: "heading", attrs: {level: 3}, content: [{type: "text", text: "Detection Source"}]}, - {type: "paragraph", content: [{type: "text", text: "Workflow Run: ", marks: [{type: "strong"}]}, {type: "text", text: $url, marks: [{type: "link", attrs: {href: $url}}]}]}, - {type: "paragraph", content: [{type: "text", text: "Commit: ", marks: [{type: "strong"}]}, {type: "text", text: $commit}]} - ] - }, - issuetype: {name: "Security Vuln"}, - components: [{name: "Instrument Python"}], - customfield_10369: $reportDate, - customfield_10374: ("[" + $cve + "]"), - customfield_10392: $vulnComponent, - labels: ["docker-scout"], - priority: {name: "Critical"} - } - }') - fi + # Build request from template + JIRA_REQUEST=$(jq \ + --arg cve "$CVE" \ + --arg pkg "$PACKAGE" \ + --arg ver "$VERSION" \ + --arg sev "$SEVERITY_TEXT" \ + --arg img "${{ steps.meta.outputs.tags[0] }}" \ + --arg msg "$MESSAGE" \ + --arg url "$WORKFLOW_URL" \ + --arg commit "${{ github.sha }}" \ + --arg summary "${CVE}: Python - ${PACKAGE}" \ + --arg teamId "$TEAM_ID" \ + --arg reportDate "$REPORT_DATE" \ + --arg cveArray "[${CVE}]" \ + --arg vulnComponent "$VULN_COMPONENT" \ + ' + walk(if type == "string" then + gsub("\\$CVE"; $cve) | + gsub("\\$PACKAGE"; $pkg) | + gsub("\\$VERSION"; $ver) | + gsub("\\$SEVERITY"; $sev) | + gsub("\\$IMAGE"; $img) | + gsub("\\$MESSAGE"; $msg) | + gsub("\\$WORKFLOW_URL"; $url) | + gsub("\\$COMMIT"; $commit) | + gsub("\\$REPORT_DATE"; $reportDate) | + gsub("\\$CVE_ARRAY"; $cveArray) | + gsub("\\$VULN_COMPONENT"; $vulnComponent) + else . end) | + .fields.summary = $summary | + if $teamId != "" then + .fields.customfield_10001 = $teamId + else . end + ' .github/templates/jira-security-vuln.json) TEMP_REQUEST=$(mktemp) printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" From 947984b010ceca717dd36a88fa1f0f9699a73191 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 16:13:32 -0700 Subject: [PATCH 14/21] Revert test mode --- ...ublish_image_autoinstrumentation_beta.yaml | 82 +++++++++---------- image/requirements.txt | 4 +- solarwinds_apm/version.py | 2 +- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index cfb548087..6644226d2 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -56,17 +56,16 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - # TEMP: Push disabled to test Jira ticket creation - # - name: Build and push - amd64, arm64 - # uses: docker/build-push-action@v7 - # with: - # push: true - # context: image - # file: image/Dockerfile-beta - # platforms: linux/amd64,linux/arm64 - # build-args: version=${{ env.VERSION }}-beta - # tags: ${{ steps.meta.outputs.tags }} - # labels: ${{ steps.meta.outputs.labels }} + - name: Build and push - amd64, arm64 + uses: docker/build-push-action@v7 + with: + push: true + context: image + file: image/Dockerfile-beta + platforms: linux/amd64,linux/arm64 + build-args: version=${{ env.VERSION }}-beta + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} - name: Build locally for scan - amd64 uses: docker/build-push-action@v7 @@ -218,34 +217,33 @@ jobs: exit 1 fi - # TEMP: ghcr.io job disabled to test Jira ticket creation - # ghcr_io: - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v7 - - # - name: Read solarwinds_apm version requirement - # run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV - - # - name: Set up QEMU - # uses: docker/setup-qemu-action@v4 - - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v4 - - # - name: Login to GitHub Package Registry - # uses: docker/login-action@v4 - # with: - # registry: ghcr.io - # username: ${{ github.actor }} - # password: ${{ secrets.GITHUB_TOKEN }} - - # - name: Build and push - # uses: docker/build-push-action@v7 - # with: - # push: true - # context: image - # file: image/Dockerfile-beta - # platforms: linux/amd64,linux/arm64 - # build-args: version=${{ env.VERSION }}-beta - # tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta + ghcr_io: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Read solarwinds_apm version requirement + run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV + + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Login to GitHub Package Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v7 + with: + push: true + context: image + file: image/Dockerfile-beta + platforms: linux/amd64,linux/arm64 + build-args: version=${{ env.VERSION }}-beta + tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta diff --git a/image/requirements.txt b/image/requirements.txt index 36446b9e3..610f1a5ea 100644 --- a/image/requirements.txt +++ b/image/requirements.txt @@ -3,8 +3,8 @@ opentelemetry-api==1.42.1 opentelemetry-sdk==1.42.1 opentelemetry-instrumentation==0.63b1 -# TEMP: force a vulnerability alert -urllib3 < 2.7.0 +urllib3 >= 2.7.0, < 3.0.0 +requests >= 2.33.0, < 3.0 # We don't use the otlp_proto_grpc option since gRPC is not appropriate for # injected auto-instrumentation, where it has a strict dependency on the OS / Python version the artifact is built for. opentelemetry-exporter-otlp-proto-http==1.42.1 diff --git a/solarwinds_apm/version.py b/solarwinds_apm/version.py index 89f1ba911..b378fc6cc 100644 --- a/solarwinds_apm/version.py +++ b/solarwinds_apm/version.py @@ -1 +1 @@ -__version__ = "7.1.0.0" +__version__ = "7.0.0" From 715cbb67f3b13c590e56ccb625f2c2e6e4c776a4 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 16:23:17 -0700 Subject: [PATCH 15/21] Add to prod image pub --- ...ild_publish_image_autoinstrumentation.yaml | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/.github/workflows/build_publish_image_autoinstrumentation.yaml b/.github/workflows/build_publish_image_autoinstrumentation.yaml index 8fd76375f..5b2844f02 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation.yaml @@ -97,6 +97,123 @@ jobs: with: sarif_file: sarif.output.json + - name: Parse SARIF for Critical/High CVEs + id: parse-cves + run: | + # Extract CVEs from SARIF + jq -r '.runs[0].results[] | + select(.level == "error" or .level == "warning") | + @json' sarif.output.json > vulnerabilities.json + + # Count vulnerabilities + echo "count=$(jq -s 'length' vulnerabilities.json)" >> $GITHUB_OUTPUT + + - name: Create Jira tickets with actionable details + if: steps.parse-cves.outputs.count > 0 + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + run: | + set +e + + TICKET_COUNT=0 + ERROR_COUNT=0 + CREATED_TICKETS=() + + while IFS= read -r vuln; do + CVE=$(echo "$vuln" | jq -r '.ruleId') + PACKAGE=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.artifactLocation.uri // "unknown"') + VERSION=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.region.snippet.text // "unknown"') + RAW_MESSAGE=$(echo "$vuln" | jq -r '.message.text') + SEVERITY=$(echo "$vuln" | jq -r '.level') + + # Sanitize MESSAGE: remove control characters but keep newlines/tabs + MESSAGE=$(echo "$RAW_MESSAGE" | tr -d '\000-\010\013\014\016-\037') + + SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") + WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + TEAM_ID="${{ secrets.JIRA_TEAM_FIELD_ID }}" + REPORT_DATE=$(date +%Y-%m-%d) + VULN_COMPONENT="${PACKAGE}-${VERSION}" + + # Build request from template + JIRA_REQUEST=$(jq \ + --arg cve "$CVE" \ + --arg pkg "$PACKAGE" \ + --arg ver "$VERSION" \ + --arg sev "$SEVERITY_TEXT" \ + --arg img "${{ steps.meta.outputs.tags[0] }}" \ + --arg msg "$MESSAGE" \ + --arg url "$WORKFLOW_URL" \ + --arg commit "${{ github.sha }}" \ + --arg summary "${CVE}: Python - ${PACKAGE}" \ + --arg teamId "$TEAM_ID" \ + --arg reportDate "$REPORT_DATE" \ + --arg cveArray "[${CVE}]" \ + --arg vulnComponent "$VULN_COMPONENT" \ + ' + walk(if type == "string" then + gsub("\\$CVE"; $cve) | + gsub("\\$PACKAGE"; $pkg) | + gsub("\\$VERSION"; $ver) | + gsub("\\$SEVERITY"; $sev) | + gsub("\\$IMAGE"; $img) | + gsub("\\$MESSAGE"; $msg) | + gsub("\\$WORKFLOW_URL"; $url) | + gsub("\\$COMMIT"; $commit) | + gsub("\\$REPORT_DATE"; $reportDate) | + gsub("\\$CVE_ARRAY"; $cveArray) | + gsub("\\$VULN_COMPONENT"; $vulnComponent) + else . end) | + .fields.summary = $summary | + if $teamId != "" then + .fields.customfield_10001 = $teamId + else . end + ' .github/templates/jira-security-vuln.json) + + TEMP_REQUEST=$(mktemp) + printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" + + JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ + -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ + -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Accept: application/json" \ + --data-binary @"$TEMP_REQUEST") + + HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) + RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') + rm -f "$TEMP_REQUEST" + + # Process response + if [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then + JIRA_KEY=$(echo "$RESPONSE_BODY" | jq -r '.key // "null"') + if [ "$JIRA_KEY" != "null" ] && [ -n "$JIRA_KEY" ]; then + CREATED_TICKETS+=("$JIRA_KEY") + ((TICKET_COUNT++)) + else + echo "❌ ${CVE}: Failed to parse ticket ID (HTTP ${HTTP_CODE})" + ((ERROR_COUNT++)) + fi + else + echo "❌ ${CVE}: HTTP ${HTTP_CODE}" + ((ERROR_COUNT++)) + fi + + done < vulnerabilities.json + + echo "=========================================" + if [ $TICKET_COUNT -gt 0 ]; then + TICKET_LIST=$(IFS=', '; echo "${CREATED_TICKETS[*]}") + echo "✅ Created ${TICKET_COUNT} tickets: ${TICKET_LIST}" + fi + + if [ $ERROR_COUNT -gt 0 ]; then + echo "❌ Failed to create ${ERROR_COUNT} tickets" + exit 1 + fi + ghcr_io: runs-on: ubuntu-latest steps: From b34621357c60651a2d2f90969543844ab7ce1cca Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 16:27:56 -0700 Subject: [PATCH 16/21] refactor shared jira_vuln action --- .github/actions/jira_vuln_k8s/action.yaml | 158 ++++++++++++++++++ ...ild_publish_image_autoinstrumentation.yaml | 126 ++------------ ...ublish_image_autoinstrumentation_beta.yaml | 129 ++------------ 3 files changed, 178 insertions(+), 235 deletions(-) create mode 100644 .github/actions/jira_vuln_k8s/action.yaml diff --git a/.github/actions/jira_vuln_k8s/action.yaml b/.github/actions/jira_vuln_k8s/action.yaml new file mode 100644 index 000000000..3fa8fc53b --- /dev/null +++ b/.github/actions/jira_vuln_k8s/action.yaml @@ -0,0 +1,158 @@ +name: 'Create JIRA Tickets for Docker Scout CVEs' +description: 'Parses Docker Scout SARIF output and creates JIRA tickets for critical/high vulnerabilities' +inputs: + image-tag: + description: 'Docker image tag that was scanned' + required: true + workflow-url: + description: 'GitHub Actions workflow URL' + required: true + commit-sha: + description: 'Git commit SHA' + required: true + jira-base-url: + description: 'JIRA base URL' + required: true + jira-user-email: + description: 'JIRA user email' + required: true + jira-api-token: + description: 'JIRA API token' + required: true + jira-team-field-id: + description: 'JIRA custom field ID for team' + required: false + default: '' +outputs: + vulnerability-count: + description: 'Number of vulnerabilities found' + value: ${{ steps.parse-cves.outputs.count }} + ticket-count: + description: 'Number of JIRA tickets created' + value: ${{ steps.create-tickets.outputs.ticket-count }} +runs: + using: 'composite' + steps: + - name: Parse SARIF for Critical/High CVEs + id: parse-cves + shell: bash + run: | + # Extract CVEs from SARIF + jq -r '.runs[0].results[] | + select(.level == "error" or .level == "warning") | + @json' sarif.output.json > vulnerabilities.json + + # Count vulnerabilities + echo "count=$(jq -s 'length' vulnerabilities.json)" >> $GITHUB_OUTPUT + + - name: Create Jira tickets with actionable details + id: create-tickets + if: steps.parse-cves.outputs.count > 0 + shell: bash + env: + JIRA_BASE_URL: ${{ inputs.jira-base-url }} + JIRA_USER_EMAIL: ${{ inputs.jira-user-email }} + JIRA_API_TOKEN: ${{ inputs.jira-api-token }} + IMAGE_TAG: ${{ inputs.image-tag }} + WORKFLOW_URL: ${{ inputs.workflow-url }} + COMMIT_SHA: ${{ inputs.commit-sha }} + TEAM_ID: ${{ inputs.jira-team-field-id }} + run: | + set +e + + TICKET_COUNT=0 + ERROR_COUNT=0 + CREATED_TICKETS=() + + while IFS= read -r vuln; do + CVE=$(echo "$vuln" | jq -r '.ruleId') + PACKAGE=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.artifactLocation.uri // "unknown"') + VERSION=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.region.snippet.text // "unknown"') + RAW_MESSAGE=$(echo "$vuln" | jq -r '.message.text') + SEVERITY=$(echo "$vuln" | jq -r '.level') + + # Sanitize MESSAGE: remove control characters but keep newlines/tabs + MESSAGE=$(echo "$RAW_MESSAGE" | tr -d '\000-\010\013\014\016-\037') + + SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") + REPORT_DATE=$(date +%Y-%m-%d) + VULN_COMPONENT="${PACKAGE}-${VERSION}" + + # Build request from template + JIRA_REQUEST=$(jq \ + --arg cve "$CVE" \ + --arg pkg "$PACKAGE" \ + --arg ver "$VERSION" \ + --arg sev "$SEVERITY_TEXT" \ + --arg img "$IMAGE_TAG" \ + --arg msg "$MESSAGE" \ + --arg url "$WORKFLOW_URL" \ + --arg commit "$COMMIT_SHA" \ + --arg summary "${CVE}: Python - ${PACKAGE}" \ + --arg teamId "$TEAM_ID" \ + --arg reportDate "$REPORT_DATE" \ + --arg cveArray "[${CVE}]" \ + --arg vulnComponent "$VULN_COMPONENT" \ + ' + walk(if type == "string" then + gsub("\\$CVE"; $cve) | + gsub("\\$PACKAGE"; $pkg) | + gsub("\\$VERSION"; $ver) | + gsub("\\$SEVERITY"; $sev) | + gsub("\\$IMAGE"; $img) | + gsub("\\$MESSAGE"; $msg) | + gsub("\\$WORKFLOW_URL"; $url) | + gsub("\\$COMMIT"; $commit) | + gsub("\\$REPORT_DATE"; $reportDate) | + gsub("\\$CVE_ARRAY"; $cveArray) | + gsub("\\$VULN_COMPONENT"; $vulnComponent) + else . end) | + .fields.summary = $summary | + if $teamId != "" then + .fields.customfield_10001 = $teamId + else . end + ' .github/templates/jira-security-vuln.json) + + TEMP_REQUEST=$(mktemp) + printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" + + JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ + -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ + -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Accept: application/json" \ + --data-binary @"$TEMP_REQUEST") + + HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) + RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') + rm -f "$TEMP_REQUEST" + + # Process response + if [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then + JIRA_KEY=$(echo "$RESPONSE_BODY" | jq -r '.key // "null"') + if [ "$JIRA_KEY" != "null" ] && [ -n "$JIRA_KEY" ]; then + CREATED_TICKETS+=("$JIRA_KEY") + ((TICKET_COUNT++)) + else + echo "❌ ${CVE}: Failed to parse ticket ID (HTTP ${HTTP_CODE})" + ((ERROR_COUNT++)) + fi + else + echo "❌ ${CVE}: HTTP ${HTTP_CODE}" + ((ERROR_COUNT++)) + fi + + done < vulnerabilities.json + + echo "=========================================" + if [ $TICKET_COUNT -gt 0 ]; then + TICKET_LIST=$(IFS=', '; echo "${CREATED_TICKETS[*]}") + echo "✅ Created ${TICKET_COUNT} tickets: ${TICKET_LIST}" + fi + + echo "ticket-count=${TICKET_COUNT}" >> $GITHUB_OUTPUT + + if [ $ERROR_COUNT -gt 0 ]; then + echo "❌ Failed to create ${ERROR_COUNT} tickets" + exit 1 + fi diff --git a/.github/workflows/build_publish_image_autoinstrumentation.yaml b/.github/workflows/build_publish_image_autoinstrumentation.yaml index 5b2844f02..cda04b05e 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation.yaml @@ -97,122 +97,16 @@ jobs: with: sarif_file: sarif.output.json - - name: Parse SARIF for Critical/High CVEs - id: parse-cves - run: | - # Extract CVEs from SARIF - jq -r '.runs[0].results[] | - select(.level == "error" or .level == "warning") | - @json' sarif.output.json > vulnerabilities.json - - # Count vulnerabilities - echo "count=$(jq -s 'length' vulnerabilities.json)" >> $GITHUB_OUTPUT - - - name: Create Jira tickets with actionable details - if: steps.parse-cves.outputs.count > 0 - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - run: | - set +e - - TICKET_COUNT=0 - ERROR_COUNT=0 - CREATED_TICKETS=() - - while IFS= read -r vuln; do - CVE=$(echo "$vuln" | jq -r '.ruleId') - PACKAGE=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.artifactLocation.uri // "unknown"') - VERSION=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.region.snippet.text // "unknown"') - RAW_MESSAGE=$(echo "$vuln" | jq -r '.message.text') - SEVERITY=$(echo "$vuln" | jq -r '.level') - - # Sanitize MESSAGE: remove control characters but keep newlines/tabs - MESSAGE=$(echo "$RAW_MESSAGE" | tr -d '\000-\010\013\014\016-\037') - - SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") - WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - TEAM_ID="${{ secrets.JIRA_TEAM_FIELD_ID }}" - REPORT_DATE=$(date +%Y-%m-%d) - VULN_COMPONENT="${PACKAGE}-${VERSION}" - - # Build request from template - JIRA_REQUEST=$(jq \ - --arg cve "$CVE" \ - --arg pkg "$PACKAGE" \ - --arg ver "$VERSION" \ - --arg sev "$SEVERITY_TEXT" \ - --arg img "${{ steps.meta.outputs.tags[0] }}" \ - --arg msg "$MESSAGE" \ - --arg url "$WORKFLOW_URL" \ - --arg commit "${{ github.sha }}" \ - --arg summary "${CVE}: Python - ${PACKAGE}" \ - --arg teamId "$TEAM_ID" \ - --arg reportDate "$REPORT_DATE" \ - --arg cveArray "[${CVE}]" \ - --arg vulnComponent "$VULN_COMPONENT" \ - ' - walk(if type == "string" then - gsub("\\$CVE"; $cve) | - gsub("\\$PACKAGE"; $pkg) | - gsub("\\$VERSION"; $ver) | - gsub("\\$SEVERITY"; $sev) | - gsub("\\$IMAGE"; $img) | - gsub("\\$MESSAGE"; $msg) | - gsub("\\$WORKFLOW_URL"; $url) | - gsub("\\$COMMIT"; $commit) | - gsub("\\$REPORT_DATE"; $reportDate) | - gsub("\\$CVE_ARRAY"; $cveArray) | - gsub("\\$VULN_COMPONENT"; $vulnComponent) - else . end) | - .fields.summary = $summary | - if $teamId != "" then - .fields.customfield_10001 = $teamId - else . end - ' .github/templates/jira-security-vuln.json) - - TEMP_REQUEST=$(mktemp) - printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" - - JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ - -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ - -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ - -H "Content-Type: application/json; charset=utf-8" \ - -H "Accept: application/json" \ - --data-binary @"$TEMP_REQUEST") - - HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) - RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') - rm -f "$TEMP_REQUEST" - - # Process response - if [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then - JIRA_KEY=$(echo "$RESPONSE_BODY" | jq -r '.key // "null"') - if [ "$JIRA_KEY" != "null" ] && [ -n "$JIRA_KEY" ]; then - CREATED_TICKETS+=("$JIRA_KEY") - ((TICKET_COUNT++)) - else - echo "❌ ${CVE}: Failed to parse ticket ID (HTTP ${HTTP_CODE})" - ((ERROR_COUNT++)) - fi - else - echo "❌ ${CVE}: HTTP ${HTTP_CODE}" - ((ERROR_COUNT++)) - fi - - done < vulnerabilities.json - - echo "=========================================" - if [ $TICKET_COUNT -gt 0 ]; then - TICKET_LIST=$(IFS=', '; echo "${CREATED_TICKETS[*]}") - echo "✅ Created ${TICKET_COUNT} tickets: ${TICKET_LIST}" - fi - - if [ $ERROR_COUNT -gt 0 ]; then - echo "❌ Failed to create ${ERROR_COUNT} tickets" - exit 1 - fi + - name: Create JIRA tickets for vulnerabilities + uses: ./.github/actions/jira_vuln_k8s + with: + image-tag: ${{ steps.meta.outputs.tags[0] }} + workflow-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + commit-sha: ${{ github.sha }} + jira-base-url: ${{ secrets.JIRA_BASE_URL }} + jira-user-email: ${{ secrets.JIRA_USER_EMAIL }} + jira-api-token: ${{ secrets.JIRA_API_TOKEN }} + jira-team-field-id: ${{ secrets.JIRA_TEAM_FIELD_ID }} ghcr_io: runs-on: ubuntu-latest diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 6644226d2..05768935d 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -97,125 +97,16 @@ jobs: with: sarif_file: sarif.output.json - - name: Parse SARIF for Critical/High CVEs - id: parse-cves - run: | - # Extract CVEs from SARIF - jq -r '.runs[0].results[] | - select(.level == "error" or .level == "warning") | - @json' sarif.output.json > vulnerabilities.json - - # Count vulnerabilities - echo "count=$(jq -s 'length' vulnerabilities.json)" >> $GITHUB_OUTPUT - - - name: Create Jira tickets with actionable details - if: steps.parse-cves.outputs.count > 0 - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - run: | - set +e - - TICKET_COUNT=0 - ERROR_COUNT=0 - CREATED_TICKETS=() - - while IFS= read -r vuln; do - CVE=$(echo "$vuln" | jq -r '.ruleId') - PACKAGE=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.artifactLocation.uri // "unknown"') - VERSION=$(echo "$vuln" | jq -r '.locations[0].physicalLocation.region.snippet.text // "unknown"') - RAW_MESSAGE=$(echo "$vuln" | jq -r '.message.text') - SEVERITY=$(echo "$vuln" | jq -r '.level') - - # Sanitize MESSAGE: remove control characters but keep newlines/tabs - MESSAGE=$(echo "$RAW_MESSAGE" | tr -d '\000-\010\013\014\016-\037') - - echo "Processing ${CVE}..." - SEVERITY_TEXT=$([ "$SEVERITY" = "error" ] && echo "Critical" || echo "High") - WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - TEAM_ID="${{ secrets.JIRA_TEAM_FIELD_ID }}" - REPORT_DATE=$(date +%Y-%m-%d) - VULN_COMPONENT="${PACKAGE}-${VERSION}" - - # Build request from template - JIRA_REQUEST=$(jq \ - --arg cve "$CVE" \ - --arg pkg "$PACKAGE" \ - --arg ver "$VERSION" \ - --arg sev "$SEVERITY_TEXT" \ - --arg img "${{ steps.meta.outputs.tags[0] }}" \ - --arg msg "$MESSAGE" \ - --arg url "$WORKFLOW_URL" \ - --arg commit "${{ github.sha }}" \ - --arg summary "${CVE}: Python - ${PACKAGE}" \ - --arg teamId "$TEAM_ID" \ - --arg reportDate "$REPORT_DATE" \ - --arg cveArray "[${CVE}]" \ - --arg vulnComponent "$VULN_COMPONENT" \ - ' - walk(if type == "string" then - gsub("\\$CVE"; $cve) | - gsub("\\$PACKAGE"; $pkg) | - gsub("\\$VERSION"; $ver) | - gsub("\\$SEVERITY"; $sev) | - gsub("\\$IMAGE"; $img) | - gsub("\\$MESSAGE"; $msg) | - gsub("\\$WORKFLOW_URL"; $url) | - gsub("\\$COMMIT"; $commit) | - gsub("\\$REPORT_DATE"; $reportDate) | - gsub("\\$CVE_ARRAY"; $cveArray) | - gsub("\\$VULN_COMPONENT"; $vulnComponent) - else . end) | - .fields.summary = $summary | - if $teamId != "" then - .fields.customfield_10001 = $teamId - else . end - ' .github/templates/jira-security-vuln.json) - - TEMP_REQUEST=$(mktemp) - printf '%s\n' "$JIRA_REQUEST" > "$TEMP_REQUEST" - - JIRA_RESPONSE=$(curl -s --http1.1 -w "\n%{http_code}" --connect-timeout 30 --max-time 90 \ - -X POST "${JIRA_BASE_URL}/rest/api/3/issue" \ - -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ - -H "Content-Type: application/json; charset=utf-8" \ - -H "Accept: application/json" \ - --data-binary @"$TEMP_REQUEST") - - HTTP_CODE=$(echo "$JIRA_RESPONSE" | tail -n1) - RESPONSE_BODY=$(echo "$JIRA_RESPONSE" | sed '$d') - rm -f "$TEMP_REQUEST" - - # Process response - if [[ "$HTTP_CODE" =~ ^2[0-9][0-9]$ ]]; then - JIRA_KEY=$(echo "$RESPONSE_BODY" | jq -r '.key // "null"') - if [ "$JIRA_KEY" != "null" ] && [ -n "$JIRA_KEY" ]; then - JIRA_URL="${JIRA_BASE_URL}/browse/${JIRA_KEY}" - echo "✅ Created ${JIRA_KEY}: ${JIRA_URL}" - CREATED_TICKETS+=("$JIRA_KEY") - ((TICKET_COUNT++)) - else - echo "❌ ${CVE}: Failed to parse ticket ID (HTTP ${HTTP_CODE})" - ((ERROR_COUNT++)) - fi - else - echo "❌ ${CVE}: HTTP ${HTTP_CODE}" - ((ERROR_COUNT++)) - fi - - done < vulnerabilities.json - - echo "=========================================" - if [ $TICKET_COUNT -gt 0 ]; then - TICKET_LIST=$(IFS=', '; echo "${CREATED_TICKETS[*]}") - echo "✅ Created ${TICKET_COUNT} tickets: ${TICKET_LIST}" - fi - - if [ $ERROR_COUNT -gt 0 ]; then - echo "❌ Failed to create ${ERROR_COUNT} tickets" - exit 1 - fi + - name: Create JIRA tickets for vulnerabilities + uses: ./.github/actions/jira_vuln_k8s + with: + image-tag: ${{ steps.meta.outputs.tags[0] }} + workflow-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + commit-sha: ${{ github.sha }} + jira-base-url: ${{ secrets.JIRA_BASE_URL }} + jira-user-email: ${{ secrets.JIRA_USER_EMAIL }} + jira-api-token: ${{ secrets.JIRA_API_TOKEN }} + jira-team-field-id: ${{ secrets.JIRA_TEAM_FIELD_ID }} ghcr_io: runs-on: ubuntu-latest From 76d45d60e8ba61bf9d61eb935097b254527756e1 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 16:29:09 -0700 Subject: [PATCH 17/21] Test again --- ...ublish_image_autoinstrumentation_beta.yaml | 80 +++++++++---------- image/requirements.txt | 4 +- solarwinds_apm/version.py | 2 +- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index 05768935d..c0fe20cdb 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -56,16 +56,16 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push - amd64, arm64 - uses: docker/build-push-action@v7 - with: - push: true - context: image - file: image/Dockerfile-beta - platforms: linux/amd64,linux/arm64 - build-args: version=${{ env.VERSION }}-beta - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + # - name: Build and push - amd64, arm64 + # uses: docker/build-push-action@v7 + # with: + # push: true + # context: image + # file: image/Dockerfile-beta + # platforms: linux/amd64,linux/arm64 + # build-args: version=${{ env.VERSION }}-beta + # tags: ${{ steps.meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} - name: Build locally for scan - amd64 uses: docker/build-push-action@v7 @@ -108,33 +108,33 @@ jobs: jira-api-token: ${{ secrets.JIRA_API_TOKEN }} jira-team-field-id: ${{ secrets.JIRA_TEAM_FIELD_ID }} - ghcr_io: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - name: Read solarwinds_apm version requirement - run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Login to GitHub Package Registry - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v7 - with: - push: true - context: image - file: image/Dockerfile-beta - platforms: linux/amd64,linux/arm64 - build-args: version=${{ env.VERSION }}-beta - tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta + # ghcr_io: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v7 + + # - name: Read solarwinds_apm version requirement + # run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV + + # - name: Set up QEMU + # uses: docker/setup-qemu-action@v4 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v4 + + # - name: Login to GitHub Package Registry + # uses: docker/login-action@v4 + # with: + # registry: ghcr.io + # username: ${{ github.actor }} + # password: ${{ secrets.GITHUB_TOKEN }} + + # - name: Build and push + # uses: docker/build-push-action@v7 + # with: + # push: true + # context: image + # file: image/Dockerfile-beta + # platforms: linux/amd64,linux/arm64 + # build-args: version=${{ env.VERSION }}-beta + # tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta diff --git a/image/requirements.txt b/image/requirements.txt index 610f1a5ea..36446b9e3 100644 --- a/image/requirements.txt +++ b/image/requirements.txt @@ -3,8 +3,8 @@ opentelemetry-api==1.42.1 opentelemetry-sdk==1.42.1 opentelemetry-instrumentation==0.63b1 -urllib3 >= 2.7.0, < 3.0.0 -requests >= 2.33.0, < 3.0 +# TEMP: force a vulnerability alert +urllib3 < 2.7.0 # We don't use the otlp_proto_grpc option since gRPC is not appropriate for # injected auto-instrumentation, where it has a strict dependency on the OS / Python version the artifact is built for. opentelemetry-exporter-otlp-proto-http==1.42.1 diff --git a/solarwinds_apm/version.py b/solarwinds_apm/version.py index b378fc6cc..89f1ba911 100644 --- a/solarwinds_apm/version.py +++ b/solarwinds_apm/version.py @@ -1 +1 @@ -__version__ = "7.0.0" +__version__ = "7.1.0.0" From ef5374bb8d73a31d475e5519efc8750f975a6a98 Mon Sep 17 00:00:00 2001 From: tammy-baylis-swi Date: Fri, 26 Jun 2026 16:33:28 -0700 Subject: [PATCH 18/21] Revert "Test again" This reverts commit 76d45d60e8ba61bf9d61eb935097b254527756e1. --- ...ublish_image_autoinstrumentation_beta.yaml | 80 +++++++++---------- image/requirements.txt | 4 +- solarwinds_apm/version.py | 2 +- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml index c0fe20cdb..05768935d 100644 --- a/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml +++ b/.github/workflows/build_publish_image_autoinstrumentation_beta.yaml @@ -56,16 +56,16 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - # - name: Build and push - amd64, arm64 - # uses: docker/build-push-action@v7 - # with: - # push: true - # context: image - # file: image/Dockerfile-beta - # platforms: linux/amd64,linux/arm64 - # build-args: version=${{ env.VERSION }}-beta - # tags: ${{ steps.meta.outputs.tags }} - # labels: ${{ steps.meta.outputs.labels }} + - name: Build and push - amd64, arm64 + uses: docker/build-push-action@v7 + with: + push: true + context: image + file: image/Dockerfile-beta + platforms: linux/amd64,linux/arm64 + build-args: version=${{ env.VERSION }}-beta + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} - name: Build locally for scan - amd64 uses: docker/build-push-action@v7 @@ -108,33 +108,33 @@ jobs: jira-api-token: ${{ secrets.JIRA_API_TOKEN }} jira-team-field-id: ${{ secrets.JIRA_TEAM_FIELD_ID }} - # ghcr_io: - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v7 - - # - name: Read solarwinds_apm version requirement - # run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV - - # - name: Set up QEMU - # uses: docker/setup-qemu-action@v4 - - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v4 - - # - name: Login to GitHub Package Registry - # uses: docker/login-action@v4 - # with: - # registry: ghcr.io - # username: ${{ github.actor }} - # password: ${{ secrets.GITHUB_TOKEN }} - - # - name: Build and push - # uses: docker/build-push-action@v7 - # with: - # push: true - # context: image - # file: image/Dockerfile-beta - # platforms: linux/amd64,linux/arm64 - # build-args: version=${{ env.VERSION }}-beta - # tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta + ghcr_io: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Read solarwinds_apm version requirement + run: echo VERSION=$(head -n 1 image/requirements-nodeps-beta.txt | cut -d '=' -f3) >> $GITHUB_ENV + + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Login to GitHub Package Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v7 + with: + push: true + context: image + file: image/Dockerfile-beta + platforms: linux/amd64,linux/arm64 + build-args: version=${{ env.VERSION }}-beta + tags: ghcr.io/${{ github.repository_owner }}/autoinstrumentation-python:${{ env.VERSION }}-beta diff --git a/image/requirements.txt b/image/requirements.txt index 36446b9e3..610f1a5ea 100644 --- a/image/requirements.txt +++ b/image/requirements.txt @@ -3,8 +3,8 @@ opentelemetry-api==1.42.1 opentelemetry-sdk==1.42.1 opentelemetry-instrumentation==0.63b1 -# TEMP: force a vulnerability alert -urllib3 < 2.7.0 +urllib3 >= 2.7.0, < 3.0.0 +requests >= 2.33.0, < 3.0 # We don't use the otlp_proto_grpc option since gRPC is not appropriate for # injected auto-instrumentation, where it has a strict dependency on the OS / Python version the artifact is built for. opentelemetry-exporter-otlp-proto-http==1.42.1 diff --git a/solarwinds_apm/version.py b/solarwinds_apm/version.py index 89f1ba911..b378fc6cc 100644 --- a/solarwinds_apm/version.py +++ b/solarwinds_apm/version.py @@ -1 +1 @@ -__version__ = "7.1.0.0" +__version__ = "7.0.0" From 48163e04cbd69001cdb154155d2054f03e530b74 Mon Sep 17 00:00:00 2001 From: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> Date: Fri, 26 Jun 2026 17:04:34 -0700 Subject: [PATCH 19/21] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/actions/jira_vuln_k8s/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/jira_vuln_k8s/action.yaml b/.github/actions/jira_vuln_k8s/action.yaml index 3fa8fc53b..48855feb3 100644 --- a/.github/actions/jira_vuln_k8s/action.yaml +++ b/.github/actions/jira_vuln_k8s/action.yaml @@ -47,7 +47,7 @@ runs: - name: Create Jira tickets with actionable details id: create-tickets - if: steps.parse-cves.outputs.count > 0 + if: steps.parse-cves.outputs.count != '0' shell: bash env: JIRA_BASE_URL: ${{ inputs.jira-base-url }} From 4efac0743babe8706232deead0b6be995f0f9748 Mon Sep 17 00:00:00 2001 From: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> Date: Fri, 26 Jun 2026 17:05:29 -0700 Subject: [PATCH 20/21] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/actions/jira_vuln_k8s/action.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/jira_vuln_k8s/action.yaml b/.github/actions/jira_vuln_k8s/action.yaml index 48855feb3..0b5346343 100644 --- a/.github/actions/jira_vuln_k8s/action.yaml +++ b/.github/actions/jira_vuln_k8s/action.yaml @@ -108,6 +108,7 @@ runs: gsub("\\$VULN_COMPONENT"; $vulnComponent) else . end) | .fields.summary = $summary | + .fields.priority.name = $sev | if $teamId != "" then .fields.customfield_10001 = $teamId else . end From 537a03498d0c605b6611308b11702738afe770c5 Mon Sep 17 00:00:00 2001 From: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> Date: Fri, 26 Jun 2026 17:06:01 -0700 Subject: [PATCH 21/21] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/templates/jira-security-vuln.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/templates/jira-security-vuln.json b/.github/templates/jira-security-vuln.json index 1a0bf5ad9..bf8292468 100644 --- a/.github/templates/jira-security-vuln.json +++ b/.github/templates/jira-security-vuln.json @@ -94,7 +94,7 @@ {"name": "Instrument Python"} ], "customfield_10369": "$REPORT_DATE", - "customfield_10374": "$CVE_ARRAY", + "customfield_10374": ["$CVE"], "customfield_10392": "$VULN_COMPONENT", "labels": ["docker-scout"], "priority": {