Jenkins Learn
06. Tích hợp công cụ

SonarQube

Tích hợp SonarQube với Jenkins để phân tích code, chờ Quality Gate và giữ bằng chứng không lộ secret.

Phạm vi và giả định

Hướng dẫn này dùng SonarQube Scanner for Jenkins plugin, SonarQube Server hoặc SonarQube Cloud đã được tổ chức phê duyệt. Tên server, plugin, scanner, webhook, project key và credential ID chỉ là minh họa. Xác minh version, network, TLS, permission và behavior trên sandbox trước khi dùng cho release.

SonarQube tạo tín hiệu về chất lượng và security của source. Jenkins chạy scanner, lưu task context và chờ kết quả Quality Gate bất đồng bộ. Một stage tên Sonar không tự chứng minh analysis đã hoàn tất, webhook đã đến hay release được phép.

Mục lục

Mục tiêu và mô hình

Sau bài này, bạn có thể nối một revision trusted Jenkins với project/branch SonarQube, chạy scanner trên agent đúng toolchain, chờ Quality Gate qua webhook có deadline, và quyết định blocking hay advisory mà không làm build xanh giả. PR/fork có thể chỉ chạy unit/coverage cô lập nếu policy không cho remote analysis. Khung policy rộng hơn nằm ở Quality Gates.

Các thành phần và ranh giới

Thành phầnTrách nhiệmKhông tự chứng minh
ScannerĐọc source, binary và report để gửi analysisCompute Engine đã xử lý task hoặc Quality Gate đã đạt.
SonarQube Server/CloudLưu project, chạy Compute Engine và đánh giá Quality GateJenkins agent, SCM trust hoặc artifact release đúng digest.
SonarQube Scanner for Jenkins pluginCấp connection vào withSonarQubeEnv và nhận Quality Gate webhookCapability Jenkins core hay mọi scanner đã được cài.
Jenkins PipelineChạy command, chờ task và quyết định flowToken, TLS, project permission hay webhook tự đúng.
WebhookBáo task/Gate result về JenkinsAuthentication của scanner hoặc branch protection SCM.
direction: down
A: "PR hoặc fork"
B: "Agent isolated: unit và coverage"
C: "Không remote Sonar, không\ncredential"
D: "Revision trusted sau merge"
E: "Agent trusted chạy scanner"
F: "SonarQube analysis report"
G: "Compute Engine task"
H: "Task terminal?" {
  shape: diamond
}
I: "Evaluate Quality Gate"
J: "Failure evidence"
K: "Webhook tới Jenkins endpoint"
L: "waitForQualityGate"
M: "Gate đạt policy?" {
  shape: diamond
}
N: "Tiếp tục lane được phép"
O: "Chặn promotion, giữ evidence"

A -> B
B -> C
D -> E
E -> F
F -> G
G -> H
H -> I: "SUCCESS"
H -> J: "FAILED or CANCELED"
I -> K
K -> L
L -> M
M -> N: "Có"
M -> O: "Không"
PR hoặc forkAgent isolated: unit và coverageKhông remote Sonar, khôngcredentialRevision trusted sau mergeAgent trusted chạy scannerSonarQube analysis reportCompute Engine taskTask terminal?Evaluate Quality GateFailure evidenceWebhook tới Jenkins endpointwaitForQualityGateGate đạt policy?Tiếp tục lane được phépChặn promotion, giữ evidence SUCCESSFAILED or CANCELEDCóKhông
PR hoặc forkAgent isolated: unit và coverageKhông remote Sonar, khôngcredentialRevision trusted sau mergeAgent trusted chạy scannerSonarQube analysis reportCompute Engine taskTask terminal?Evaluate Quality GateFailure evidenceWebhook tới Jenkins endpointwaitForQualityGateGate đạt policy?Tiếp tục lane được phépChặn promotion, giữ evidence SUCCESSFAILED or CANCELEDCóKhông
Các thành phần và ranh giới

Repository này render D2 lúc build qua source.config.ts; sơ đồ mô tả flow, không phải bằng chứng runtime integration đã chạy.

Server và Cloud

SonarQube Server là instance do tổ chức vận hành; SonarQube Cloud là dịch vụ SaaS. Cả hai đều dùng project, analysis, Compute Engine và Quality Gate theo capability/version tương ứng, nhưng URL, organization, authentication, network, plan và administration khác nhau.

Điều cần xác địnhServerCloud
EndpointURL canonical của instance, có thể có context path/proxyURL/organization chính thức của Cloud theo tài liệu hiện hành.
TLS/CAController/agent trust CA nội bộ qua image/OS managedKiểm tra TLS công khai và egress policy.
Quản trịOwner vận hành database, upgrade, plugin/edition và webhook routeOrganization owner quản lý project/member/token theo dịch vụ.
CompatibilityKiểm tra version Server, scanner và Jenkins pluginKiểm tra documented Cloud integration/scanner version và organization binding.

Không thay Server bằng Cloud chỉ bằng cách đổi URL. Ghi loại dịch vụ, URL canonical, version/capability, owner và test evidence trong connection record.

Kết nối, identity và project

Jenkins server configuration

SonarQube Scanner for Jenkins plugin thêm cấu hình server vào Jenkins và step withSonarQubeEnv. Trên controller sandbox, tạo connection có tên minh họa sonarqube-sandbox, URL đã xác minh và credential reference do Jenkins quản lý. Plugin, Jenkins core, Java, scanner và global configuration là prerequisite runtime; pin/review chúng như dependency controller, không cài plugin chỉ để mẫu Jenkinsfile parse.

withSonarQubeEnv('sonarqube-sandbox') đặt environment connection trong closure cho scanner. Nó không cài scanner, không checkout source, không tự tạo project và không biến token thành an toàn cho code không tin cậy. Lấy exact snippet từ Pipeline Syntax của controller vì credential type/configuration có thể khác theo plugin version.

Project key, branch và Pull Request

Project key là identity ổn định của project analysis. Chọn key reviewable, ownership rõ và không đổi theo mỗi branch/build. Mỗi analysis phải liên kết với revision SHA, scanner version, project key và branch/PR context; nếu không, Quality Gate có thể là kết quả của source khác.

  • Main/branch analysis: gửi tên branch theo integration/scanner đã support. Branch protected sau merge thường là nơi hợp lý cho release blocking gate.
  • Pull Request analysis: cần key/branch base và PR identity do scanner/integration chính thức hỗ trợ. Nó đánh giá thay đổi PR theo context PR, không tự thay branch analysis.
  • Không tự bịa property: tên/availability các property branch/PR thay đổi theo scanner, edition/Cloud và build integration. Dùng scanner documentation/version của dự án, không chép property từ GitLab CI vào Jenkinsfile.

Từ Jenkins Multibranch, metadata PR/branch có thể do source plugin cung cấp. Xác minh source SHA, target/base và variables trên sandbox trước khi map sang scanner. PR từ fork vẫn là code không tin cậy; không cấp token có capability write, deploy hoặc release chỉ để analysis tiện hơn.

Token, TLS và rotation

Token scanner là capability gửi analysis đến SonarQube, không phải biến để commit vào sonar-project.properties, Jenkinsfile, command line hay URL. Dùng Jenkins credential reference được connection/plugin hỗ trợ, scope hẹp ở folder/job, và chỉ cấp quyền tối thiểu theo project/organization. Service identity riêng tốt hơn token cá nhân hoặc administrator dùng chung.

  • không echo, printenv, set -x, Groovy interpolation, -Dsonar.token=..., query URL hay debug HTTP có token;
  • giữ TLS verification và CA trust đúng; không dùng curl -k, ignoreSslErrors hoặc tắt certificate check;
  • ghi owner, purpose, project scope, credential ID/reference, expiry/review date và revoke path;
  • rotate qua token mới trong sandbox, chuyển consumer có kiểm soát, xác minh analysis/webhook, rồi revoke token cũ;
  • không chạy source PR/fork trên agent cùng user/workspace với lane có token release hoặc token SonarQube quyền rộng.

Masking console chỉ là defense-in-depth. Credential, agent trust, network egress và quyền sửa Jenkinsfile là các control riêng; xem Credentials & Secrets.

Chạy scanner đúng ngữ cảnh

Scanner khác Compute Engine

Scanner chạy trên Jenkins agent: nó đọc checkout, build output và report rồi upload analysis. Upload thành công chỉ cho biết server đã nhận request/task reference. Compute Engine (CE) chạy sau đó ở SonarQube để xử lý analysis và tính Quality Gate. Vì CE bất đồng bộ, không suy luận sh scanner exit code 0 là Quality Gate pass.

CE task thường đi qua trạng thái chờ/chạy như PENDING hoặc IN_PROGRESS, rồi terminal SUCCESS, FAILED hay CANCELED theo API/version. Chỉ task SUCCESS mới là cơ sở để đọc Quality Gate result. FAILED hoặc CANCELED là evidence failure/inconclusive cần giữ; không retry scanner mù để biến CE failure thành pass.

Maven, Gradle, CLI và Node

Chọn launcher theo build system đã dùng, pin phiên bản tool/plugin và ghi toolchain agent. Các command dưới chỉ là mẫu sau khi project, scanner và report path đã được xác minh; không có command nào tự tạo coverage hoặc project metadata đúng.

Dự ánLauncher phù hợpĐiều phải pin/xác minh
MavenMaven goal của SonarScanner for Maven, ví dụ mvn -B -ntp sonar:sonar khi plugin/project đã cấu hìnhMaven, JDK, plugin Maven, project key/connection và report coverage.
GradleGradle task scanner do project/plugin Gradle cung cấp, thường là ./gradlew sonarGradle wrapper, JDK, plugin/configuration và task name của version đang dùng.
Bất kỳ build system nàoSonarScanner CLI với sonar-project.properties hoặc properties được reviewCLI binary/version, required binaries, project key và paths relative workspace.
JavaScript/TypeScript/NodeDùng scanner integration đã support cho project Node; Node là runtime analyzer dependency chứ không phải lời hứa có một Jenkins step “Node scanner” chungNode version, lockfile, test/coverage report và scanner documentation/version.

Không thêm -Dsonar.login, -Dsonar.token hay token tương tự vào sh để chữa lỗi auth. Khi withSonarQubeEnv cung cấp credential theo integration runtime, để scanner đọc môi trường/cấu hình đã review mà không in biến. Nếu tool bắt buộc một secret trong argv, thiết kế lại integration hoặc dùng descriptor/file an toàn; đừng chấp nhận lộ token.

Coverage và evidence

SonarQube đọc coverage report do test tool tạo; scanner không chạy unit test thay bạn. Chạy test trước scanner, kiểm report tồn tại, revision đúng và paths tương đối. Coverage/new-code threshold là policy Quality Gate hoặc policy release; không hạ rule cho một PR mà không review version policy.

Lưu evidence tối thiểu: revision SHA, project key, branch/PR identity, scanner/CE/gate outcome, policy version, Jenkins build URL và timestamp. Không archive toàn workspace, scanner cache, environment dump, raw HTTP log hoặc credential file. Report có thể chứa source path/metadata nhạy cảm nên access/retention phải phù hợp.

Webhook và Quality Gate bất đồng bộ

Endpoint, authenticity và delivery

Để waitForQualityGate nhận kết quả, cấu hình webhook ở SonarQube tới chính xác:

$JENKINS_URL/sonarqube-webhook/

Dấu / cuối là một phần endpoint được Jenkins integration công bố. JENKINS_URL phải là URL public canonical mà SonarQube reach được qua DNS, TLS, reverse proxy và context path. Không thay nó bằng URL localhost của controller nếu SonarQube chạy ở mạng khác.

Webhook là capability plugin, không phải Jenkins core. Cài SonarQube Scanner for Jenkins plugin, cấu hình connection và webhook trên sandbox trước. Nếu version SonarQube/plugin hỗ trợ webhook secret/HMAC, cấu hình cùng secret theo tài liệu của hai đầu và kiểm tra verification behavior bằng delivery sandbox; không log secret/header/body. Một webhook secret xác thực callback, không cấp quyền scanner hoặc thay TLS/network policy.

Ghi delivery evidence đã redact: task/component logical reference, response outcome, delivery time, Jenkins build URL và plugin/server version. Không giữ token, secret header, full payload, query có secret hoặc console dump để “debug webhook”.

Trạng thái task và quyết định gate

SignalÝ nghĩaQuyết định Pipeline đề xuất
CE PENDING/IN_PROGRESSAnalysis chưa có kết quả terminalChờ webhook trong timeout, không publish success.
CE SUCCESS, Gate OKCE xử lý xong và gate đạtTiếp tục lane được policy cho phép.
CE SUCCESS, Gate không đạtAnalysis hoàn tất nhưng policy chất lượng không đạtChặn gate blocking bằng abortPipeline: true.
CE FAILEDServer không xử lý được analysisFail/inconclusive theo policy, giữ task evidence; không làm xanh.
CE CANCELEDTask bị hủyGiữ abort/cancel semantics; điều tra trước rerun.
Không nhận webhook trước deadlineKhông có bằng chứng gate hoàn tấtTimeout/fail closed cho release blocking; sửa delivery.

Webhook có thể bị delivery lại hoặc đến sau khi Pipeline đã timeout. Plugin/server chịu trách nhiệm liên kết task context theo version; không tự poll một endpoint không được review, không trigger publish/deploy trong webhook callback và không retry waitForQualityGate như một test assertion. Khi callback bị duplicate, side effect release phải vẫn deduplicate theo revision/artifact digest.

Jenkins Pipeline chặn release trung thực

Prerequisite và Jenkinsfile

Mẫu cần Pipeline: Declarative, SonarQube Scanner for Jenkins plugin, connection Jenkins tên sonarqube-sandbox, scanner/toolchain phù hợp, agent cô lập untrusted-pr-linux không có credential, release cache hay network capability SonarQube, agent trusted-analysis-linux dành cho revision sau merge, webhook SonarQube tới $JENKINS_URL/sonarqube-webhook/, và project/report paths đã xác minh. withSonarQubeEnv và waitForQualityGate là steps của plugin, không phải Jenkins core.

pipeline {
  agent none

  options {
    skipDefaultCheckout(true)
    timeout(time: 30, unit: 'MINUTES')
  }

  stages {
    stage('PR unit test and coverage') {
      when {
        beforeAgent true
        changeRequest()
      }
      agent { label 'untrusted-pr-linux' }
      steps {
        checkout scm
        sh 'mvn -B -ntp test'
      }
      post {
        always {
          // Chỉ giữ report đã xác định; không archive source, cache hay environment dump.
          junit allowEmptyResults: false,
            testResults: 'target/surefire-reports/*.xml'
          archiveArtifacts allowEmptyArchive: true,
            artifacts: 'target/surefire-reports/**,target/site/**',
            fingerprint: true
          deleteDir()
        }
      }
    }

    stage('Trusted branch test and Sonar analysis') {
      when {
        beforeAgent true
        allOf {
          not { changeRequest() }
          branch 'main'
        }
      }
      agent { label 'trusted-analysis-linux' }
      steps {
        checkout scm
        sh 'mvn -B -ntp test'
        // Scanner đọc source và coverage report trong chính workspace trusted này.
        withSonarQubeEnv('sonarqube-sandbox') {
          sh 'mvn -B -ntp sonar:sonar'
        }
      }
      post {
        always {
          junit allowEmptyResults: false,
            testResults: 'target/surefire-reports/*.xml'
          archiveArtifacts allowEmptyArchive: true,
            artifacts: 'target/surefire-reports/**,target/site/**',
            fingerprint: true
          deleteDir()
        }
      }
    }

    stage('Quality Gate for trusted branch') {
      when {
        beforeAgent true
        allOf {
          not { changeRequest() }
          branch 'main'
        }
      }
      options {
        timeout(time: 10, unit: 'MINUTES')
      }
      steps {
        waitForQualityGate abortPipeline: true
      }
    }

    stage('Protected release action') {
      when {
        beforeAgent true
        branch 'main'
      }
      agent { label 'trusted-release-linux' }
      steps {
        checkout scm
        sh './ci/verify-release-policy'
      }
    }
  }
}

beforeAgent true làm changeRequest() được xét trước khi Jenkins cấp agent: PR/fork chỉ checkout và chạy Maven trên untrusted-pr-linux, không có withSonarQubeEnv, scanner, remote server query, trusted cache hay credential binding. Trusted branch test and Sonar analysis và Quality Gate for trusted branch dùng cùng điều kiện nên PR bị skip không thể gọi waitForQualityGate thiếu task context.

branch 'main' không tự chứng minh trust: điều kiện này chỉ đủ khi Multibranch source, branch protection và merge queue/required review của SCM đảm bảo main là revision đã được merge theo policy; direct push, job parameter override và unprotected tag phải bị cấm hoặc dùng trusted job riêng. Nếu tổ chức cần remote PR analysis, tách một job/agent/network/credential scope riêng đã được security review; không nới mẫu này bằng cách bỏ changeRequest().

Scanner đọc source và coverage report trong chính workspace trusted-analysis-linux. Quality Gate stage không cần checkout; nó chờ callback plugin trên controller. Cả post block chỉ archive report explicit rồi deleteDir() để dọn workspace; không archive source, cache hoặc environment. Protected release stage tự checkout revision selected by SCM vì agent none và stage agent có thể dùng workspace khác. Không chuyển source từ MR/fork vào release workspace qua stash/unstash.

Timeout, abort, retry và unstable

waitForQualityGate abortPipeline: true làm Pipeline dừng khi plugin nhận Quality Gate không đạt, theo semantics plugin/version. Bao step bằng timeout để webhook sai URL, proxy/TLS lỗi hoặc CE treo không chờ vô hạn. Timeout/abort là interruption cần lan truyền; không bọc required gate bằng catchError rồi đi đến release.

Không dùng retry quanh scanner blocking, waitForQualityGate, test hoặc release chỉ để giảm build đỏ. Retry chỉ phù hợp với thao tác read-only/idempotent đã có bằng chứng lỗi tạm thời, số attempt hữu hạn và deadline. CE FAILED/CANCELED hoặc webhook timeout cần evidence, owner và remediation; rerun sau khi sửa nguyên nhân là build mới, không xóa failure cũ.

UNSTABLE chỉ phù hợp signal advisory đã được policy định nghĩa, ví dụ một metric mới đang baseline. Nó không được map thành SUCCESS, không được mở protected release, và phải giữ evidence/owner/expiry. Xử lý lỗi và Retry mô tả exit code, timeout, abort và catchError chi tiết.

PR, branch bảo vệ và trust

Mẫu này chọn không chạy remote SonarQube analysis cho PR/fork: PR chỉ có unit/coverage trên agent cô lập và không có withSonarQubeEnv, nên không có Quality Gate remote để claim là đã phân tích. Scanner token có quyền write/project vẫn là secret; chỉ cấp nó cho source trust tier đã được policy phê duyệt, không cho fork code tùy ý. Nếu cần remote PR analysis, dùng job/agent/network/credential scope tách biệt đã qua security review; không tái sử dụng trusted-analysis-linux hay token branch sau merge.

Protected branch sau merge chạy gate blocking, rồi mới vào release lane. branch 'main' trong Jenkinsfile chỉ là điều kiện Multibranch; nó chỉ an toàn khi SCM branch protection/merge queue và Jenkins authorization đã được kiểm chứng. Kết hợp SCM required review/status, Jenkins authorization, agent isolation, credential scope và artifact provenance. Không để PR unit result hay PR Quality Gate (nếu có workflow tách riêng) cấp publish/sign/deploy capability.

Evidence, retention và vận hành

Mỗi decision giữ project key logical, source SHA, branch/PR context, scanner/plugin/server version, CE task outcome, Quality Gate outcome, policy version, Jenkins build URL, webhook delivery result đã redact và owner. Tách retention cho task metadata, console log, coverage report, artifact và audit/change record. Không archive scanner cache hoặc full workspace vì có thể chứa data/credential tạm.

Alert cho token expiry, scanner upload error, CE failed/canceled, webhook delivery failure, Jenkins timeout, Quality Gate failure, duplicate delivery và drift version plugin/server. Khi update Server/Cloud configuration, scanner, Jenkins plugin, reverse proxy hay CA, chạy analysis và gate sandbox trước. Một build xanh trước update không chứng minh webhook mapping sau update vẫn đúng.

Lab local với kết quả giả

Lab tạo fixture Compute Engine/Quality Gate JSON và Jenkinsfile text giả, rồi validator mô phỏng pending, pass, fail và timeout. Nó không có SonarQube, Jenkins, token, network, webhook listener hay scanner. Cần shell POSIX và Python 3; dùng WORKSPACE là parent local riêng do bạn sở hữu.

Fixture CE và Quality Gate

set -eu
umask 077

: "${WORKSPACE:?Set WORKSPACE to a dedicated local lab parent}"
WORKSPACE="$(cd -- "$WORKSPACE" && pwd -P)"
test -d "$WORKSPACE"
LAB_PREFIX='jenkins-sonarqube-lab.'
LAB_ROOT="$(mktemp -d "${WORKSPACE%/}/${LAB_PREFIX}XXXXXX")"
LAB_ROOT="$(cd -- "$LAB_ROOT" && pwd -P)"
case "$LAB_ROOT" in
  "${WORKSPACE%/}/${LAB_PREFIX}"*) ;;
  *) printf 'Refuse unexpected lab path: %s\n' "$LAB_ROOT" >&2; exit 1 ;;
esac
[ "$(dirname -- "$LAB_ROOT")" = "$WORKSPACE" ] || {
  printf 'Refuse non-direct WORKSPACE child: %s\n' "$LAB_ROOT" >&2
  exit 1
}
: > "$LAB_ROOT/.lab-owned"

cat > "$LAB_ROOT/ce-pending.json" <<'EOF'
{"task":{"id":"training-task-pending","status":"PENDING","componentKey":"training:demo"}}
EOF
cat > "$LAB_ROOT/ce-success.json" <<'EOF'
{"task":{"id":"training-task-pass","status":"SUCCESS","componentKey":"training:demo"}}
EOF
cat > "$LAB_ROOT/gate-pass.json" <<'EOF'
{"projectStatus":{"status":"OK","conditions":[]}}
EOF
cat > "$LAB_ROOT/gate-fail.json" <<'EOF'
{"projectStatus":{"status":"ERROR","conditions":[{"metricKey":"new_coverage","status":"ERROR"}]}}
EOF
cat > "$LAB_ROOT/Jenkinsfile.fixture" <<'EOF'
pipeline {
  agent none
  stages {
    stage('PR unit') {
      when { beforeAgent true; changeRequest() }
      agent { label 'untrusted-pr-linux' }
      steps { checkout scm; sh 'mvn -B -ntp test' }
    }
    stage('Trusted analysis') {
      when {
        beforeAgent true
        allOf { not { changeRequest() }; branch 'main' }
      }
      agent { label 'trusted-analysis-linux' }
      steps {
        checkout scm
        withSonarQubeEnv('sonarqube-sandbox') {
          sh 'mvn -B -ntp sonar:sonar'
        }
      }
    }
    stage('Gate') {
      when {
        beforeAgent true
        allOf { not { changeRequest() }; branch 'main' }
      }
      options { timeout(time: 10, unit: 'MINUTES') }
      steps { waitForQualityGate abortPipeline: true }
    }
  }
}
EOF

python3 - "$LAB_ROOT" <<'PY'
import json
import pathlib
import sys

root = pathlib.Path(sys.argv[1])
pending = json.loads((root / 'ce-pending.json').read_text())
success = json.loads((root / 'ce-success.json').read_text())
passed = json.loads((root / 'gate-pass.json').read_text())
failed = json.loads((root / 'gate-fail.json').read_text())
jenkinsfile = (root / 'Jenkinsfile.fixture').read_text()
assert pending['task']['status'] == 'PENDING'
assert success['task']['status'] == 'SUCCESS'
assert passed['projectStatus']['status'] == 'OK'
assert failed['projectStatus']['status'] == 'ERROR'
assert "withSonarQubeEnv('sonarqube-sandbox')" in jenkinsfile
assert "agent { label 'untrusted-pr-linux' }" in jenkinsfile
assert "agent { label 'trusted-analysis-linux' }" in jenkinsfile
assert jenkinsfile.count('beforeAgent true') == 3
assert jenkinsfile.count('changeRequest()') == 3
assert 'waitForQualityGate abortPipeline: true' in jenkinsfile
assert 'timeout(time: 10' in jenkinsfile
print('pending: waiting (simulated)')
print('pass: Quality Gate OK (simulated)')
print('fail: Quality Gate ERROR; blocking (simulated)')
print('timeout: no webhook before deadline; fail closed (simulated)')
PY
printf 'Lab fixture directory: %s\n' "$LAB_ROOT"

Kết quả mong đợi là bốn dòng simulated outcome. Fixture fail vẫn làm validator thành công vì nó xác minh policy phải nhận biết ERROR; nó không mô phỏng Jenkins build xanh. Lab không xác minh webhook endpoint, HMAC/secret verification, CE queue, SonarQube UI, scanner command, token, TLS hay plugin runtime.

Kết quả và cleanup có guard

Chạy cleanup trong cùng shell sau khi đọc fixture. Guard canonicalize WORKSPACE và LAB_ROOT, xác nhận prefix, marker và quan hệ child trực tiếp trước rm -rf. Không dùng block này cho JENKINS_HOME, workspace build thật, volume, source repository hay path người dùng nhập.

set -eu
: "${WORKSPACE:?Run the creation block in this shell}"
: "${LAB_ROOT:?Run the creation block in this shell}"
WORKSPACE="$(cd -- "$WORKSPACE" && pwd -P)"
test -d "$WORKSPACE"
test -d "$LAB_ROOT"
LAB_ROOT="$(cd -- "$LAB_ROOT" && pwd -P)"
LAB_PREFIX='jenkins-sonarqube-lab.'

case "$LAB_ROOT" in
  "${WORKSPACE%/}/${LAB_PREFIX}"*)
    [ "$(dirname -- "$LAB_ROOT")" = "$WORKSPACE" ] || {
      printf 'Refuse cleanup outside direct WORKSPACE child: %s\n' "$LAB_ROOT" >&2
      exit 1
    }
    test -f "$LAB_ROOT/.lab-owned"
    test -f "$LAB_ROOT/ce-pending.json"
    rm -rf -- "$LAB_ROOT"
    printf 'Removed guarded SonarQube training fixture.\n'
    ;;
  *)
    printf 'Refuse cleanup outside lab prefix: %s\n' "$LAB_ROOT" >&2
    exit 1
    ;;
esac

Troubleshooting

Dấu hiệuKiểm tra bằng evidenceHành động an toàn
withSonarQubeEnv không được nhận diệnPlugin short name/version, Pipeline Syntax, controller logCài/review plugin qua change process; không thay bằng secret hard-code.
Scanner upload lỗi auth/TLSURL canonical, CA, service identity scope/expiry, agent egress và audit thời điểmSửa trust/token scope, rotate khi cần; không in token hoặc tắt TLS.
Scanner exit 0 nhưng Gate chưa cóCE task reference/status, project key, webhook delivery, plugin/server versionChờ waitForQualityGate trong timeout; không suy diễn scanner pass là gate pass.
waitForQualityGate timeout$JENKINS_URL/sonarqube-webhook/, trailing slash, DNS/proxy/TLS, callback responseSửa callback trên sandbox, giữ build timeout/failure; không bypass gate.
Gate fail nhưng release vẫn chạyabortPipeline, catchError, when, build/stage result và policyĐể exception chặn flow; tách advisory khỏi required gate.
PR workflow tách riêng đè branch resultProject key, PR/branch properties, source/base SHA, agent/credential scope và scanner capabilitySửa mapping theo supported integration; giữ workflow remote PR tách trusted branch, hoặc để mẫu này chỉ chạy unit/coverage PR.
CE FAILED/CANCELEDTask metadata, server health/log đã redact, capacity và version changeGhi inconclusive/failure, sửa nguyên nhân rồi rerun mới; không làm xanh lần cũ.
Report/log có secret hoặc source nhạy cảmArchive glob, scanner debug, environment dump và credential scopeDừng publish, redact/rotate theo incident policy, chỉ giữ evidence tối thiểu.

Checklist áp dụng

  • Server hoặc Cloud, URL canonical, version/capability, owner, TLS/CA, network/egress và sandbox evidence được ghi rõ.
  • SonarQube Scanner for Jenkins, Pipeline, scanner/build tool, JDK/Node và agent image có version pin, advisory review và compatibility test.
  • Project key ổn định; branch/PR/source/base revision mapping dùng property/integration được version hiện hành support.
  • Token nằm trong Jenkins credential/configuration scope hẹp, có owner/rotation/revoke; không ở Jenkinsfile, argv, URL, log, artifact hay fixture.
  • changeRequest() có beforeAgent true chọn agent cô lập không credential/cache/release; mọi withSonarQubeEnv, scanner và remote SonarQube query chỉ ở trusted branch/job condition đã review.
  • branch 'main'/tag/merge-queue condition được đối chiếu với branch protection, source trigger và Jenkins authorization; condition tên branch một mình không được coi là trust proof.
  • Scanner command, test và coverage report chạy theo toolchain thật; scanner exit code không bị gọi sai là Quality Gate pass.
  • SonarQube webhook trỏ đúng $JENKINS_URL/sonarqube-webhook/, có TLS/proxy/delivery verification và secret/HMAC khi supported/configured.
  • waitForQualityGate abortPipeline: true chạy sau scanner, trong timeout; timeout, abort, CE fail/cancel và gate fail không biến thành success.
  • Retry không che test/scanner/gate/release failure; duplicate delivery/rebuild không tạo side effect release trùng.
  • PR/fork không tin cậy không nhận capability release; mẫu này chỉ chạy unit/coverage PR và chỉ protected branch sau merge mới vào lane remote gate/release đã tách trust.
  • Evidence có revision/project/task/gate/policy/plugin reference và retention/ACL; report/archive không chứa secret hay full workspace không cần thiết.
  • Lab chỉ tạo JSON/Jenkinsfile fixture local với marker/prefix/direct-parent guard; không gọi SonarQube/Jenkins/webhook thật.

Tự kiểm tra

  1. Scanner exit 0 chứng minh gì, và tại sao chưa đủ để release? Nêu vai trò Compute Engine, webhook và Quality Gate.
  2. Vì sao waitForQualityGate abortPipeline: true cần timeout, và timeout không được bọc để release tiếp?
  3. Token scanner, webhook secret và credential deploy khác nhau ở capability nào? Vì sao không dùng một token chung?
  4. PR source SHA và branch protected sau merge cần project/analysis context khác nhau ra sao? Khi nào không cấp scanner token cho fork?
  5. CE CANCELED khác Quality Gate ERROR thế nào, và evidence/decision nào phải giữ cho từng case?
  6. Khi webhook delivery bị lặp, thao tác nào có thể quan sát lại và side effect release nào phải deduplicate theo revision/digest?

Nguồn chính thức

Đọc tiếp

On this page