Skip to content

Commit a80b302

Browse files
authored
ci: fetch Sonar token from Azure Key Vault via OIDC (#26)
* ci: fetch Sonar token from Azure Key Vault via OIDC * ci: scope Sonar token to scan steps after tests * ci: gate Sonar secret access to trusted PR contexts * ci: guard Sonar secrets on trusted PRs only * ci: retrigger checks after org required workflow policy * ci: retrigger required workflow gate * ci: retrigger after required-workflow fix * ci: satisfy required zizmor workflow policy
1 parent 9c072d0 commit a80b302

2 files changed

Lines changed: 44 additions & 11 deletions

File tree

.github/workflows/dependency-review.yml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,17 @@ on:
2020
# https://docs.github.com/en/enterprise-cloud@latest/code-security/supply-chain-security/understanding-your-software-supply-chain/using-the-dependency-submission-api
2121
permissions:
2222
contents: read
23-
# Write permissions for pull-requests are required for using the `comment-summary-in-pr` option, comment out if you aren't using this option
24-
pull-requests: write
2523

2624
jobs:
2725
dependency-review:
2826
runs-on: ubuntu-latest
2927
steps:
3028
- name: 'Checkout repository'
31-
uses: actions/checkout@v6
29+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
3230
- name: 'Dependency Review'
33-
uses: actions/dependency-review-action@v4
31+
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4
3432
# Commonly enabled options, see https://github.com/actions/dependency-review-action#configuration-options for all available options.
35-
with:
36-
comment-summary-in-pr: always
33+
# No PR comment output to keep permissions read-only.
3734
# fail-on-severity: moderate
3835
# deny-licenses: GPL-1.0-or-later, LGPL-2.0-or-later
3936
# retry-on-snapshot-warnings: true

.github/workflows/sonarcloud.yml

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@ on:
66
push:
77
branches:
88
- main
9+
permissions: {}
910

1011
jobs:
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

Comments
 (0)