Skip to content

SonarCloud

SonarCloud #17315

Workflow file for this run

name: SonarCloud
on:
# workflow_run is required to run analysis on PRs from forks with access to
# secrets; the job recreates the merge state from trusted metadata and does
# not execute untrusted PR code.
workflow_run: # zizmor: ignore[dangerous-triggers]
workflows: [Analysis]
types: [completed]
permissions:
actions: read
contents: read
pull-requests: read
jobs:
sonarcloud:
name: SonarCloud
runs-on: ubuntu-latest
container: ghcr.io/acts-project/ubuntu2404:87
if: github.event.workflow_run.conclusion == 'success'
steps:
- name: Install APT packages
run: |
apt-get update
apt-get install -y unzip
- name: "Checkout repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0 # To prevent shallow clone
persist-credentials: false
- name: Install dependencies
uses: ./.github/actions/dependencies
with:
compiler: g++
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
env_file: .env
- name: 'Download artifact'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
id: dl-af
with:
script: |
console.log(`Getting artifacts for workflow run id: ${context.payload.workflow_run.id}`);
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
for (artifact of allArtifacts.data.artifacts) {
console.log(`Artifact #${artifact.id} ${artifact.name}`);
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data));
}
return true;
- name: Unzip coverage build
run: unzip coverage-build.zip -d build
- name: Unzip PR metadata
if: github.event.workflow_run.event == 'pull_request'
run: unzip PR_metadata.zip
- name: Read PR metadata
if: github.event.workflow_run.event == 'pull_request'
id: pr_metadata
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const fs = require('fs');
const metadata = JSON.parse(fs.readFileSync('PR_metadata.json', 'utf8'));
console.log('PR metadata:', JSON.stringify(metadata, null, 2));
core.setOutput('pr_number', metadata.pr_number);
core.setOutput('pr_sha', metadata.pr_sha);
core.setOutput('base_sha', metadata.base_sha);
core.setOutput('merge_sha', metadata.merge_sha);
- name: Request GitHub API for PR data
if: github.event.workflow_run.event == 'pull_request'
uses: octokit/request-action@b91aabaa861c777dcdb14e2387e30eddf04619ae # v3.0.0
id: get_pr_data
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
route: GET /repos/{full_name}/pulls/{number}
number: ${{ steps.pr_metadata.outputs.pr_number }}
full_name: ${{ github.event.repository.full_name }}
- name: Validate PR branch names
if: github.event.workflow_run.event == 'pull_request'
env:
HEAD_REF: ${{ fromJson(steps.get_pr_data.outputs.data).head.ref }}
BASE_REF: ${{ fromJson(steps.get_pr_data.outputs.data).base.ref }}
run: |
# These values are attacker-controlled (the PR branch name) and are
# passed to sonar-scanner as CLI arguments below. Reject anything that
# isn't a well-formed git ref to prevent argument injection.
for ref in "$HEAD_REF" "$BASE_REF"; do
case "$ref" in
""|*[!A-Za-z0-9._/-]*)
echo "Refusing to proceed: unexpected branch name '$ref'" >&2
exit 1
;;
esac
done
- name: Get upcoming version from milestones
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: acts-project/acts
run: |
CI/get_next_milestone.py | tee next_version.txt
- name: Read next_version.txt
id: next_version
uses: juliangruber/read-file-action@271ff311a4947af354c6abcd696a306553b9ec18 # v1.1.8
with:
path: ./next_version.txt
- name: Recreate merge commit state
if: github.event.workflow_run.event == 'pull_request'
env:
PR_CLONE_URL: ${{ fromJson(steps.get_pr_data.outputs.data).head.repo.clone_url }}
BASE_SHA: ${{ steps.pr_metadata.outputs.base_sha }}
PR_SHA: ${{ steps.pr_metadata.outputs.pr_sha }}
MERGE_SHA: ${{ steps.pr_metadata.outputs.merge_sha }}
run: |
git config --global --add safe.directory $PWD
git config user.email "ci@acts-project.org"
git config user.name "CI"
# upstream: main branch, origin: PR branch
git remote rename origin upstream
git remote add origin "$PR_CLONE_URL"
git fetch origin
# Check out the exact base commit that was used in the original merge
git checkout "$BASE_SHA"
# Merge the PR commit to recreate the same merge state as the analysis run
git merge --no-edit "$PR_SHA"
# Restore the trusted scanner configuration: the merged tree contains
# attacker-controlled files, and sonar-scanner reads
# sonar-project.properties from the working directory. Reset it to the
# base commit so the PR cannot override scanner settings.
git checkout "$BASE_SHA" -- sonar-project.properties
echo "Recreated merge state:"
echo " Base SHA: $BASE_SHA"
echo " PR SHA: $PR_SHA"
echo " Current HEAD: $(git rev-parse HEAD)"
echo " Original merge SHA: $MERGE_SHA"
git remote -v
git status
- name: Run sonar-scanner (PR mode)
uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0
if: github.event.workflow_run.event == 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
--define sonar.verbose=true
--define sonar.cfamily.compile-commands=build/compile_commands.json
--define sonar.projectVersion=${{ steps.next_version.outputs.content }}
--define sonar.scm.revision=${{ steps.pr_metadata.outputs.merge_sha }}
--define sonar.pullrequest.key=${{ steps.pr_metadata.outputs.pr_number }}
--define sonar.pullrequest.branch=${{ fromJson(steps.get_pr_data.outputs.data).head.ref }}
--define sonar.pullrequest.base=${{ fromJson(steps.get_pr_data.outputs.data).base.ref }}
- name: Run sonar-scanner (push mode)
uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0
if: github.event.workflow_run.event == 'push' && github.ref == 'refs/heads/main'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
--define sonar.verbose=true
--define sonar.cfamily.compile-commands=build/compile_commands.json
--define sonar.coverageReportPaths=build/coverage/cov.xml
--define sonar.projectVersion=${{ steps.next_version.outputs.content }}
--define sonar.branch.name=main