-
Notifications
You must be signed in to change notification settings - Fork 0
feat: regression testing system (Phase 1) — 5 scenarios x 4 SQ versions #127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| name: 'Setup Ephemeral SonarQube' | ||
| description: 'Starts a SonarQube Enterprise container with PostgreSQL, restores a DB dump if available, or runs a fresh scan.' | ||
|
|
||
| inputs: | ||
| sq-version: | ||
| description: 'SonarQube version (9.9, 10.0, 10.4, 2025.1)' | ||
| required: true | ||
| sq-license-key: | ||
| description: 'SonarQube Enterprise license key' | ||
| required: true | ||
| db-dump-artifact: | ||
| description: 'Name of the DB dump artifact to restore (empty = fresh scan)' | ||
| required: false | ||
| default: '' | ||
|
|
||
| outputs: | ||
| sq-url: | ||
| description: 'URL of the running SonarQube instance' | ||
| value: ${{ steps.wait-healthy.outputs.sq-url }} | ||
| sq-token: | ||
| description: 'Admin token for the SonarQube instance' | ||
| value: ${{ steps.create-token.outputs.sq-token }} | ||
|
|
||
| runs: | ||
| using: 'composite' | ||
| steps: | ||
| - name: Create Docker network | ||
| shell: bash | ||
| run: docker network create sq-net 2>/dev/null || true | ||
|
|
||
| - name: Start PostgreSQL | ||
| shell: bash | ||
| run: | | ||
| docker run -d --name sq-postgres --network sq-net \ | ||
| -e POSTGRES_USER=sonar \ | ||
| -e POSTGRES_PASSWORD=sonar \ | ||
| -e POSTGRES_DB=sonarqube \ | ||
| postgres:15-alpine | ||
| echo "Waiting for PostgreSQL..." | ||
| for i in $(seq 1 30); do | ||
| docker exec sq-postgres pg_isready -U sonar && break | ||
| sleep 1 | ||
| done | ||
|
|
||
| - name: Restore DB dump (if provided) | ||
| if: inputs.db-dump-artifact != '' | ||
| shell: bash | ||
| run: | | ||
| echo "Restoring DB dump from artifact..." | ||
| docker exec -i sq-postgres psql -U sonar -d sonarqube < /tmp/sq-dump-${{ inputs.sq-version }}.sql | ||
| echo "Verifying restore..." | ||
| ROW_COUNT=$(docker exec sq-postgres psql -U sonar -d sonarqube -t -c "SELECT count(*) FROM projects;" 2>/dev/null | tr -d ' ' || echo "0") | ||
| echo "Projects in DB: $ROW_COUNT" | ||
| if [ "$ROW_COUNT" = "0" ]; then | ||
| echo "ERROR: DB restore failed (0 projects found)" | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Start SonarQube Enterprise | ||
| shell: bash | ||
| run: | | ||
| docker run -d --name sonarqube --network sq-net \ | ||
| -e SONAR_JDBC_URL=jdbc:postgresql://sq-postgres:5432/sonarqube \ | ||
| -e SONAR_JDBC_USERNAME=sonar \ | ||
| -e SONAR_JDBC_PASSWORD=sonar \ | ||
| -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true \ | ||
| -e SONAR_WEB_JAVAADDITIONALOPTS="-Xmx2g" \ | ||
| -p 9000:9000 \ | ||
| sonarqube:${{ inputs.sq-version }}-enterprise | ||
| echo "SonarQube ${{ inputs.sq-version }} Enterprise starting..." | ||
|
|
||
| - name: Wait for healthy | ||
| id: wait-healthy | ||
| shell: bash | ||
| run: | | ||
| for i in $(seq 1 120); do | ||
| HEALTH=$(curl -s http://localhost:9000/api/system/status 2>/dev/null | grep -o '"status":"[^"]*"' | head -1 || echo "") | ||
| if echo "$HEALTH" | grep -q "UP"; then | ||
| echo "SonarQube is UP" | ||
| echo "sq-url=http://localhost:9000" >> "$GITHUB_OUTPUT" | ||
| break | ||
| fi | ||
| echo " Waiting for UP... ($i/120) status: $HEALTH" | ||
| sleep 2 | ||
| done | ||
| if ! echo "$HEALTH" | grep -q "UP"; then | ||
| echo "ERROR: SonarQube did not become healthy within 240 seconds" | ||
| docker logs sonarqube --tail 50 | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Inject license key | ||
| shell: bash | ||
| run: | | ||
| echo "Injecting Enterprise license..." | ||
| RESULT=$(curl -s -u admin:admin -X POST \ | ||
| "http://localhost:9000/api/editions/set_license" \ | ||
| -d "license=${{ inputs.sq-license-key }}") | ||
| if echo "$RESULT" | grep -q '"errors"'; then | ||
| echo "WARNING: License injection may have failed: $RESULT" | ||
| else | ||
| echo "License injected successfully" | ||
| fi | ||
|
|
||
| - name: Create admin token | ||
| id: create-token | ||
| shell: bash | ||
| run: | | ||
| TOKEN_RESPONSE=$(curl -s -u admin:admin \ | ||
| -X POST "http://localhost:9000/api/user_tokens/generate" \ | ||
| -d "name=regression-test-$(date +%s)" \ | ||
| -d "type=GLOBAL_ANALYSIS_TOKEN") | ||
| TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) | ||
| if [ -z "$TOKEN" ]; then | ||
| echo "ERROR: Failed to create SQ token" | ||
| echo "$TOKEN_RESPONSE" | ||
| exit 1 | ||
| fi | ||
| echo "sq-token=$TOKEN" >> "$GITHUB_OUTPUT" | ||
| echo "SQ admin token created" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| name: Regression - Bug Fix Scenarios | ||
|
|
||
| on: | ||
| workflow_call: | ||
|
|
||
| concurrency: | ||
| group: regression-bug-fixes-${{ github.ref }} | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| bug-fix-scenarios: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| max-parallel: 4 | ||
| matrix: | ||
| scenario: | ||
| - name: large-project-10k-plus | ||
| issues: '#53, #94, #98' | ||
| command: migrate | ||
| - name: github-actions-language | ||
| issues: '#88' | ||
| command: migrate | ||
| - name: external-analyzers | ||
| issues: '#56, #82' | ||
| command: migrate | ||
| - name: issue-sync-first-migration | ||
| issues: '#91' | ||
| command: migrate | ||
| - name: kill-and-continue | ||
| issues: '#15, #57' | ||
| command: migrate | ||
| sq_version: | ||
| - id: '9.9' | ||
| secret_key: '9_9' | ||
| - id: '10.0' | ||
| secret_key: '10_0' | ||
| - id: '10.4' | ||
| secret_key: '10_4' | ||
| - id: '2025.1' | ||
| secret_key: '2025_1' | ||
|
|
||
| env: | ||
| SCENARIO: ${{ matrix.scenario.name }} | ||
| SQ_VERSION: ${{ matrix.sq_version.id }} | ||
| SQC_TARGET_KEY: cv-regression-${{ matrix.scenario.name }}-sq${{ matrix.sq_version.secret_key }} | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
|
|
||
| - name: Restore dependencies | ||
| uses: ./.github/actions/restore-deps | ||
|
|
||
| - name: Setup ephemeral SonarQube | ||
| id: sq-setup | ||
| uses: ./.github/actions/setup-sonarqube | ||
| with: | ||
| sq-version: ${{ matrix.sq_version.id }} | ||
| sq-license-key: ${{ secrets[format('SONARQUBE_{0}_LICENSE_KEY', matrix.sq_version.secret_key)] }} | ||
|
|
||
| - name: Generate config | ||
| uses: ./.github/actions/generate-config | ||
| env: | ||
| SONARQUBE_URL: ${{ steps.sq-setup.outputs.sq-url }} | ||
| SONARQUBE_TOKEN: ${{ steps.sq-setup.outputs.sq-token }} | ||
| SONARCLOUD_URL: ${{ secrets.SONARCLOUD_URL }} | ||
| SONARCLOUD_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }} | ||
| SONARCLOUD_ORG_KEY: ${{ secrets.SONARCLOUD_ORG_KEY }} | ||
| SONARCLOUD_ENTERPRISE_KEY: ${{ secrets.SONARCLOUD_ENTERPRISE_KEY }} | ||
|
|
||
| - name: Patch config with target key | ||
| shell: bash | ||
| run: node test/regression/helpers/patch-config.js "$SQC_TARGET_KEY" "${{ steps.sq-setup.outputs.sq-url }}" "${{ steps.sq-setup.outputs.sq-token }}" | ||
|
|
||
| - name: Cleanup SQC target project | ||
| shell: bash | ||
| run: node test/regression/helpers/cleanup-project.js "$SQC_TARGET_KEY" | ||
|
|
||
| - name: Enrich test data - Add issue comments | ||
| if: success() | ||
| run: node test/regression/enrichment/add-issue-comments.js | ||
| env: | ||
| SQ_PROJECT_KEY: angular | ||
|
|
||
| - name: Enrich test data - Change issue statuses | ||
| if: success() | ||
| run: node test/regression/enrichment/change-issue-status.js | ||
| env: | ||
| SQ_PROJECT_KEY: angular | ||
|
|
||
| - name: Enrich test data - Add hotspot data | ||
| if: success() | ||
| run: node test/regression/enrichment/add-hotspot-data.js | ||
| env: | ||
| SQ_PROJECT_KEY: angular | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Workflow enrichment fails on empty SonarQube instanceHigh Severity The workflow starts a fresh, empty SonarQube instance (no Additional Locations (2)Reviewed by Cursor Bugbot for commit d751b0c. Configure here. |
||
|
|
||
| - name: Run migration | ||
| if: matrix.scenario.name != 'kill-and-continue' | ||
| run: npm run ${{ matrix.scenario.command }} -- -c migrate-config.json --verbose | ||
|
|
||
| - name: Run migration (kill-and-continue) | ||
| if: matrix.scenario.name == 'kill-and-continue' | ||
| shell: bash | ||
| run: | | ||
| timeout --signal=SIGTERM 60s npm run migrate -- -c migrate-config.json --verbose || true | ||
| echo "Resuming after SIGTERM..." | ||
| npm run migrate -- -c migrate-config.json --verbose | ||
|
|
||
| - name: Assert results | ||
| run: node test/regression/assert-${{ matrix.scenario.name }}.js --config migrate-config.json | ||
|
|
||
| - name: Upload logs on failure | ||
| if: failure() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: regression-logs-${{ matrix.scenario.name }}-sq${{ matrix.sq_version.secret_key }} | ||
| path: migration-output/logs/ | ||
| retention-days: 7 | ||
|
|
||
| - name: Teardown containers | ||
| if: always() | ||
| shell: bash | ||
| run: | | ||
| docker stop sonarqube sq-postgres 2>/dev/null || true | ||
| docker rm sonarqube sq-postgres 2>/dev/null || true | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong token type blocks enrichment script API access
High Severity
The token is created with
type=GLOBAL_ANALYSIS_TOKEN, which is scoped exclusively to scanner analysis operations (submitting reports via/api/ce/submit). However, the enrichment scripts and migration tool need full user-level API access — including/api/issues/search,/api/issues/add_comment,/api/issues/do_transition,/api/hotspots/search, and/api/hotspots/change_status. AGLOBAL_ANALYSIS_TOKENcannot perform these operations, causing 403 errors. The type needs to beUSER_TOKEN(or omitted entirely, which defaults toUSER_TOKEN).Additional Locations (1)
.github/workflows/regression-bug-fixes.yml#L84-L101Reviewed by Cursor Bugbot for commit d751b0c. Configure here.