66 push :
77 branches :
88 - main
9+ permissions : {}
910
1011jobs :
1112 sonarcloud :
1213 runs-on : ubuntu-latest
14+ environment : org-prod
1315 permissions :
16+ id-token : write
1417 contents : read
1518 pull-requests : write
1619 steps :
17- - uses : actions/checkout@v6
20+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
1821 with :
1922 fetch-depth : 0
2023
21- - uses : actions/setup-python@v6
24+ - uses : actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
2225 with :
2326 python-version : ' 3.12'
2427
@@ -28,11 +31,43 @@ jobs:
2831 - name : Run tests with coverage
2932 run : make coverage-sonar
3033
34+ - name : Skip SonarCloud on untrusted fork PR
35+ if : ${{ github.event_name == 'pull_request' && (github.event.pull_request.head.repo.fork || !contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) }}
36+ run : |
37+ echo "Skipping SonarCloud token retrieval for untrusted PR context."
38+ echo "Fork PRs and non-collaborator authors do not receive Vault-backed token access."
39+
40+ - name : Azure login (OIDC)
41+ if : ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.fork == false && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) }}
42+ uses : azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5
43+ with :
44+ client-id : ${{ vars.AZURE_CLIENT_ID }}
45+ tenant-id : ${{ vars.AZURE_TENANT_ID }}
46+ subscription-id : ${{ vars.AZURE_SUBSCRIPTION_ID }}
47+
48+ - name : Read SonarCloud token from Key Vault
49+ if : ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.fork == false && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) }}
50+ id : sonar_token
51+ shell : bash
52+ run : |
53+ set -euo pipefail
54+ SONAR_TOKEN="$(az keyvault secret show \
55+ --vault-name "${{ vars.AZURE_KEYVAULT_NAME }}" \
56+ --name "sonar-cloud-token" \
57+ --query value -o tsv)"
58+ if [ -z "${SONAR_TOKEN}" ]; then
59+ echo "Key Vault secret sonar-cloud-token is empty."
60+ exit 1
61+ fi
62+ echo "::add-mask::$SONAR_TOKEN"
63+ echo "value=$SONAR_TOKEN" >> "$GITHUB_OUTPUT"
64+
3165 - name : SonarCloud scan
32- uses : SonarSource/sonarcloud-github-action@ffc3010689be73b8e5ae0c57ce35968afd7909e8
66+ if : ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.fork == false && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) }}
67+ uses : SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 # v7.0.0
3368 env :
3469 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
35- SONAR_TOKEN : ${{ secrets.SONAR_TOKEN }}
70+ SONAR_TOKEN : ${{ steps.sonar_token.outputs.value }}
3671 with :
3772 args : >
3873 -Dsonar.host.url=https://sonarcloud.io
@@ -43,10 +78,11 @@ jobs:
4378 -Dsonar.enableIssueAnnotation=true
4479
4580 - name : SonarCloud quality gate
81+ if : ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.fork == false && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) }}
4682 uses : SonarSource/sonarqube-quality-gate-action@cf038b0e0cdecfa9e56c198bbb7d21d751d62c3b
4783 with :
4884 scanMetadataReportFile : dist/quality/sonar/scannerwork/report-task.txt
4985 env :
50- SONAR_TOKEN : ${{ secrets.SONAR_TOKEN }}
86+ SONAR_TOKEN : ${{ steps.sonar_token.outputs.value }}
5187 SONAR_HOST_URL : https://sonarcloud.io
5288 timeout-minutes : 5
0 commit comments