From 64105c159c6163cd74b26974e37d16acc66a0667 Mon Sep 17 00:00:00 2001 From: Jeff Leach Date: Mon, 2 Mar 2026 15:49:02 -0800 Subject: [PATCH 1/5] Add workflow to gate on sonarcloud --- .github/workflows/sonarcloud-gate.yml | 99 +++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 .github/workflows/sonarcloud-gate.yml diff --git a/.github/workflows/sonarcloud-gate.yml b/.github/workflows/sonarcloud-gate.yml new file mode 100644 index 00000000..99e30c07 --- /dev/null +++ b/.github/workflows/sonarcloud-gate.yml @@ -0,0 +1,99 @@ +name: SonarCloud Blocker Check + +on: + pull_request: + branches: + - development + - main + - master + +jobs: + blocker-check: + name: SonarCloud Blocker Check + runs-on: ubuntu-latest + # Skip fork PRs (no access to SONAR_TOKEN) + if: github.event.pull_request.head.repo.full_name == github.repository + + steps: + - name: Check for BLOCKER issues + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + PR_NUMBER="${{ github.event.pull_request.number }}" + PROJECT_KEY="NASA-AMMOS_MMGIS" + MAX_ATTEMPTS=20 + SLEEP_SECONDS=15 + + echo "Checking SonarCloud for BLOCKER issues on PR #${PR_NUMBER}" + + # Poll until SonarCloud has analyzed this PR + for attempt in $(seq 1 $MAX_ATTEMPTS); do + echo "Attempt ${attempt}/${MAX_ATTEMPTS}: Querying SonarCloud..." + + # Check if SonarCloud has analysis data for this PR + ANALYSIS_RESPONSE=$(curl -s -u "${SONAR_TOKEN}:" \ + "https://sonarcloud.io/api/qualitygates/project_status?projectKey=${PROJECT_KEY}&pullRequest=${PR_NUMBER}") + + ANALYSIS_STATUS=$(echo "$ANALYSIS_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('projectStatus', {}).get('status', 'NONE'))" 2>/dev/null || echo "NONE") + + if [ "$ANALYSIS_STATUS" = "OK" ] || [ "$ANALYSIS_STATUS" = "ERROR" ]; then + echo "SonarCloud analysis complete (gate status: ${ANALYSIS_STATUS})." + break + fi + + if [ "$attempt" -eq "$MAX_ATTEMPTS" ]; then + echo "Timed out after $((MAX_ATTEMPTS * SLEEP_SECONDS))s waiting for SonarCloud analysis." + exit 1 + fi + + echo " Analysis not ready yet. Waiting ${SLEEP_SECONDS}s..." + sleep $SLEEP_SECONDS + done + + # Query for BLOCKER issues on this PR's new code + ISSUES_RESPONSE=$(curl -s -u "${SONAR_TOKEN}:" \ + "https://sonarcloud.io/api/issues/search?projectKeys=${PROJECT_KEY}&pullRequest=${PR_NUMBER}&severities=BLOCKER&statuses=OPEN,CONFIRMED,REOPENED&ps=1") + + BLOCKER_COUNT=$(echo "$ISSUES_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('total', -1))" 2>/dev/null || echo "-1") + + echo "" + echo "BLOCKER issues found: ${BLOCKER_COUNT}" + + if [ "$BLOCKER_COUNT" = "-1" ]; then + echo "ERROR: Failed to parse SonarCloud response." + echo "$ISSUES_RESPONSE" + exit 1 + elif [ "$BLOCKER_COUNT" = "0" ]; then + echo "No BLOCKER issues found. Check passed." + exit 0 + else + echo "BLOCKER issues detected! Fetching details..." + echo "" + + # Fetch up to 10 blocker issues with details + DETAILS=$(curl -s -u "${SONAR_TOKEN}:" \ + "https://sonarcloud.io/api/issues/search?projectKeys=${PROJECT_KEY}&pullRequest=${PR_NUMBER}&severities=BLOCKER&statuses=OPEN,CONFIRMED,REOPENED&ps=10") + + echo "$DETAILS" | python3 -c " + import sys, json + data = json.load(sys.stdin) + for issue in data.get('issues', []): + component = issue.get('component', '').replace('${PROJECT_KEY}:', '') + line = issue.get('line', '?') + msg = issue.get('message', 'No message') + rule = issue.get('rule', '?') + print(f' [{rule}] {component}:{line} — {msg}') + " + echo "" + echo "Fix these BLOCKER issues before merging." + exit 1 + fi + + - name: Summary + if: always() + run: | + echo "### SonarCloud Blocker Check" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "PR #${{ github.event.pull_request.number }} was checked for BLOCKER-severity issues." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "[View in SonarCloud](https://sonarcloud.io/summary/new_code?id=NASA-AMMOS_MMGIS&pullRequest=${{ github.event.pull_request.number }})" >> $GITHUB_STEP_SUMMARY From 9b35b84c2ffa6dedf8eb586679e2b11e56e4e56d Mon Sep 17 00:00:00 2001 From: Jeff Leach Date: Mon, 2 Mar 2026 15:56:32 -0800 Subject: [PATCH 2/5] Make longer pauses --- .github/workflows/sonarcloud-gate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud-gate.yml b/.github/workflows/sonarcloud-gate.yml index 99e30c07..12618526 100644 --- a/.github/workflows/sonarcloud-gate.yml +++ b/.github/workflows/sonarcloud-gate.yml @@ -22,7 +22,7 @@ jobs: PR_NUMBER="${{ github.event.pull_request.number }}" PROJECT_KEY="NASA-AMMOS_MMGIS" MAX_ATTEMPTS=20 - SLEEP_SECONDS=15 + SLEEP_SECONDS=30 echo "Checking SonarCloud for BLOCKER issues on PR #${PR_NUMBER}" From 6f76673acb36d1b4847225e740b329cc4c620319 Mon Sep 17 00:00:00 2001 From: Jeff Leach Date: Wed, 4 Mar 2026 08:09:21 -0800 Subject: [PATCH 3/5] Workflow updates for sonarcube PR block --- .github/workflows/sonarcloud-gate.yml | 45 +++++++++++++++++---------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/.github/workflows/sonarcloud-gate.yml b/.github/workflows/sonarcloud-gate.yml index 12618526..2e3a2a9b 100644 --- a/.github/workflows/sonarcloud-gate.yml +++ b/.github/workflows/sonarcloud-gate.yml @@ -1,21 +1,32 @@ -name: SonarCloud Blocker Check +name: SonarCloud Security Gate on: pull_request: + types: [opened, synchronize, reopened] branches: - development - main - master jobs: - blocker-check: - name: SonarCloud Blocker Check + security-gate: + name: SonarCloud Security Gate runs-on: ubuntu-latest # Skip fork PRs (no access to SONAR_TOKEN) if: github.event.pull_request.head.repo.full_name == github.repository steps: - - name: Check for BLOCKER issues + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: SonarCloud Scan + uses: SonarSource/sonarqube-scan-action@v6 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + - name: Check for security BLOCKER issues env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | @@ -24,13 +35,12 @@ jobs: MAX_ATTEMPTS=20 SLEEP_SECONDS=30 - echo "Checking SonarCloud for BLOCKER issues on PR #${PR_NUMBER}" + echo "Checking SonarCloud for security BLOCKER issues on PR #${PR_NUMBER}" - # Poll until SonarCloud has analyzed this PR + # Poll until SonarCloud has processed the analysis for this PR for attempt in $(seq 1 $MAX_ATTEMPTS); do echo "Attempt ${attempt}/${MAX_ATTEMPTS}: Querying SonarCloud..." - # Check if SonarCloud has analysis data for this PR ANALYSIS_RESPONSE=$(curl -s -u "${SONAR_TOKEN}:" \ "https://sonarcloud.io/api/qualitygates/project_status?projectKey=${PROJECT_KEY}&pullRequest=${PR_NUMBER}") @@ -50,29 +60,29 @@ jobs: sleep $SLEEP_SECONDS done - # Query for BLOCKER issues on this PR's new code + # Query for BLOCKER security issues on this PR's new code ISSUES_RESPONSE=$(curl -s -u "${SONAR_TOKEN}:" \ - "https://sonarcloud.io/api/issues/search?projectKeys=${PROJECT_KEY}&pullRequest=${PR_NUMBER}&severities=BLOCKER&statuses=OPEN,CONFIRMED,REOPENED&ps=1") + "https://sonarcloud.io/api/issues/search?projectKeys=${PROJECT_KEY}&pullRequest=${PR_NUMBER}&severities=BLOCKER&types=VULNERABILITY&tags=security&statuses=OPEN,CONFIRMED,REOPENED&ps=1") BLOCKER_COUNT=$(echo "$ISSUES_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('total', -1))" 2>/dev/null || echo "-1") echo "" - echo "BLOCKER issues found: ${BLOCKER_COUNT}" + echo "Security BLOCKER issues found: ${BLOCKER_COUNT}" if [ "$BLOCKER_COUNT" = "-1" ]; then echo "ERROR: Failed to parse SonarCloud response." echo "$ISSUES_RESPONSE" exit 1 elif [ "$BLOCKER_COUNT" = "0" ]; then - echo "No BLOCKER issues found. Check passed." + echo "No security BLOCKER issues found. Check passed." exit 0 else - echo "BLOCKER issues detected! Fetching details..." + echo "Security BLOCKER issues detected! Fetching details..." echo "" # Fetch up to 10 blocker issues with details DETAILS=$(curl -s -u "${SONAR_TOKEN}:" \ - "https://sonarcloud.io/api/issues/search?projectKeys=${PROJECT_KEY}&pullRequest=${PR_NUMBER}&severities=BLOCKER&statuses=OPEN,CONFIRMED,REOPENED&ps=10") + "https://sonarcloud.io/api/issues/search?projectKeys=${PROJECT_KEY}&pullRequest=${PR_NUMBER}&severities=BLOCKER&types=VULNERABILITY&tags=security&statuses=OPEN,CONFIRMED,REOPENED&ps=10") echo "$DETAILS" | python3 -c " import sys, json @@ -82,18 +92,19 @@ jobs: line = issue.get('line', '?') msg = issue.get('message', 'No message') rule = issue.get('rule', '?') - print(f' [{rule}] {component}:{line} — {msg}') + tags = ', '.join(issue.get('tags', [])) + print(f' [{rule}] {component}:{line} — {msg} (tags: {tags})') " echo "" - echo "Fix these BLOCKER issues before merging." + echo "Fix these security BLOCKER issues before merging." exit 1 fi - name: Summary if: always() run: | - echo "### SonarCloud Blocker Check" >> $GITHUB_STEP_SUMMARY + echo "### SonarCloud Security Gate" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "PR #${{ github.event.pull_request.number }} was checked for BLOCKER-severity issues." >> $GITHUB_STEP_SUMMARY + echo "PR #${{ github.event.pull_request.number }} was checked for security BLOCKER issues." >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "[View in SonarCloud](https://sonarcloud.io/summary/new_code?id=NASA-AMMOS_MMGIS&pullRequest=${{ github.event.pull_request.number }})" >> $GITHUB_STEP_SUMMARY From c132f3aacf8513322596be6ef876cb34d6b4f201 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 4 Mar 2026 16:09:49 +0000 Subject: [PATCH 4/5] chore: bump version to 4.2.16-20260304 [version bump] --- configure/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure/package.json b/configure/package.json index d6fb3bdc..9e2c3941 100644 --- a/configure/package.json +++ b/configure/package.json @@ -1,6 +1,6 @@ { "name": "configure", - "version": "4.2.15-20260302", + "version": "4.2.16-20260304", "homepage": "./configure/build", "private": true, "dependencies": { diff --git a/package.json b/package.json index 32db245e..191e325f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mmgis", - "version": "4.2.15-20260302", + "version": "4.2.16-20260304", "description": "A web-based mapping and localization solution for science operation on planetary missions.", "homepage": "build", "repository": { From bbbc02e193baa8f222699490d3345dcd125d1ccb Mon Sep 17 00:00:00 2001 From: Jeff Leach Date: Wed, 4 Mar 2026 08:24:51 -0800 Subject: [PATCH 5/5] Update scanning paths --- sonar-project.properties | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 13b9841c..2316a777 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -16,7 +16,7 @@ sonar.links.ci=https://github.com/NASA-AMMOS/MMGIS/actions # Source directories to analyze # Note: 'public' directory excluded from sources to reduce LOC - contains mostly static assets (SVGs, images, config files) # Note: 'auxiliary' directory excluded from sources - contains standalone utility scripts, not server code -sonar.sources=src,API,scripts,views,configure +sonar.sources=src,API,scripts,views,configure,spice # Note: sonar.tests is not set because test files are intermixed with source files. # Test files are excluded via sonar.test.exclusions patterns below. @@ -50,7 +50,9 @@ sonar.exclusions=\ **/public/**,\ **/auxiliary/**,\ **/images/**,\ - **/fonts/** + **/fonts/**,\ + **/examples/**,\ + **/.github/** # Test exclusions sonar.test.exclusions=\