diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..86137bd --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +Please be aware that we are not actively looking for feature contributions. +The truth is that it's extremely difficult for someone outside SonarSource to comply with our roadmap and expectations. +Therefore, we typically only accept minor cosmetic changes and typo fixes. +If you would like to see a new feature, please create a new thread in the forum ["Suggest new features"](https://community.sonarsource.com/c/suggestions/features). + +With that in mind, if you would like to submit a code contribution, make sure that you adhere to the following guidelines and all tests are passing: + +- [ ] Please explain your motives to contribute this change: what problem you are trying to fix, what improvement you are trying to make +- [ ] Make sure any code you changed is covered by tests +- [ ] If there is a [JIRA](http://jira.sonarsource.com/browse/SONAR) ticket available, please make your commits and pull request start with the ticket ID (SONAR-XXXX) + +We will try to give you feedback on your contribution as quickly as possible. + +Thank You! +The SonarSource Team diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..b83b160 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,371 @@ +name: Tests +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +jobs: + create-install-dir-test: + name: create_install_path.sh script test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Existing + shell: bash + env: + INSTALL_PATH: '.sonar' + run: | + echo "- Create dir" + mkdir -p "${INSTALL_PATH}" + + echo "- Test script behavior" + ./scripts/create_install_path.sh > output + grep -v "::error::" output + + - name: Non-existing nested in current dir + shell: bash + env: + INSTALL_PATH: '.sonar' + run: | + ./scripts/create_install_path.sh > output + grep -v "::error::" output + test -d "${INSTALL_PATH}" + + - name: Nonexisting nested in home + shell: bash + env: + INSTALL_PATH: '~/third_party/.sonar' + run: | + ./scripts/create_install_path.sh > output + grep -v "::error::" output + test -d "${INSTALL_PATH}" + + - name: Empty install dir specified + shell: bash + env: + INSTALL_PATH: '' + run: | + (./scripts/create_install_path.sh || echo "=== Script failed ===") > output + grep "::error::Empty installation path specified" output + grep "=== Script failed ===" output + + - name: No permission to create directory + shell: bash + env: + INSTALL_PATH: '/non_creatable' + run: | + (./scripts/create_install_path.sh || echo "=== Script failed ===") > output + grep "::error::Failed to create non-existing installation path '/non_creatable'" output + grep "=== Script failed ===" output + + - name: Existing but not directory + shell: bash + env: + INSTALL_PATH: 'not_directory' + run: | + echo "- Create normal file" + echo "content" > "${INSTALL_PATH}" + + echo "- Test script behavior" + (./scripts/create_install_path.sh || echo "=== Script failed ===") > output + grep "::error::Installation path 'not_directory' is not a directory" output + grep "=== Script failed ===" output + + + - name: Existing but not readable + shell: bash + env: + INSTALL_PATH: 'not_readable' + run: | + echo "- Create dir and make it not readable" + mkdir -p "${INSTALL_PATH}" + chmod -r "${INSTALL_PATH}" + + echo "- Test script behavior" + (./scripts/create_install_path.sh || echo "=== Script failed ===") > output + grep "::error::Installation path 'not_readable' is not readable" output + grep "=== Script failed ===" output + + - name: Existing but not writeable + shell: bash + env: + INSTALL_PATH: 'not_writeable' + run: | + echo "- Create dir and make it not writeable" + mkdir -p "${INSTALL_PATH}" + chmod -w "${INSTALL_PATH}" + + echo "- Test script behavior" + (./scripts/create_install_path.sh || echo "=== Script failed ===") > output + grep "::error::Installation path 'not_writeable' is not writeable" output + grep "=== Script failed ===" output + + setup-script-test: + name: configure_paths.sh script test + runs-on: ubuntu-latest + env: + INSTALL_PATH: 'install-directory' + SONAR_HOST_URL: 'http://sonar-host.com' + SONAR_SCANNER_VERSION: 'vX.Y.Z.MMMM' + SONAR_SCANNER_URL_WINDOWS: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-vX.Y.Z.MMMM-windows.zip' + SONAR_SCANNER_SHA_WINDOWS: 'DOWNLOAD-SHA-WINDOWS' + SONAR_SCANNER_URL_LINUX: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-vX.Y.Z.MMMM-linux.zip' + SONAR_SCANNER_SHA_LINUX: 'DOWNLOAD-SHA-LINUX' + SONAR_SCANNER_URL_MACOSX: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-vX.Y.Z.MMMM-macosx.zip' + SONAR_SCANNER_SHA_MACOSX: 'DOWNLOAD-SHA-MACOSX' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Windows + shell: bash + env: + OS: 'Windows' + ARCH: 'X64' + run: | + ./scripts/configure_paths.sh > output + grep -v "::error::" output + + echo "- Check sonar-scanner:" + grep "sonar-scanner-url=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-vX.Y.Z.MMMM-windows.zip" output + grep "sonar-scanner-sha=DOWNLOAD-SHA-WINDOWS" output + grep "sonar-scanner-dir=install-directory/sonar-scanner-vX.Y.Z.MMMM-windows" output + grep "sonar-scanner-bin=install-directory/sonar-scanner-vX.Y.Z.MMMM-windows/bin/sonar-scanner.bat" output + + echo "- Check build-wrapper:" + grep "build-wrapper-url=http://sonar-host.com/static/cpp/build-wrapper-win-x86.zip" output + grep "build-wrapper-dir=install-directory/build-wrapper-win-x86" output + grep "build-wrapper-bin=install-directory/build-wrapper-win-x86/build-wrapper-win-x86-64.exe" output + + - name: Linux + shell: bash + env: + OS: 'Linux' + ARCH: 'X64' + run: | + ./scripts/configure_paths.sh > output + grep -v "::error::" output + + echo "- Check sonar-scanner:" + grep "sonar-scanner-url=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-vX.Y.Z.MMMM-linux.zip" output + grep "sonar-scanner-sha=DOWNLOAD-SHA-LINUX" output + grep "sonar-scanner-dir=install-directory/sonar-scanner-vX.Y.Z.MMMM-linux" output + grep "sonar-scanner-bin=install-directory/sonar-scanner-vX.Y.Z.MMMM-linux/bin/sonar-scanner" output + + echo "- Check build-wrapper:" + grep "build-wrapper-url=http://sonar-host.com/static/cpp/build-wrapper-linux-x86.zip" output + grep "build-wrapper-dir=install-directory/build-wrapper-linux-x86" output + grep "build-wrapper-bin=install-directory/build-wrapper-linux-x86/build-wrapper-linux-x86-64" output + + - name: macOSX + shell: bash + env: + OS: 'macOS' + ARCH: 'X64' + run: | + ./scripts/configure_paths.sh > output + grep -v "::error::" output + + echo "- Check sonar-scanner:" + grep "sonar-scanner-url=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-vX.Y.Z.MMMM-macosx.zip" output + grep "sonar-scanner-sha=DOWNLOAD-SHA-MACOSX" output + grep "sonar-scanner-dir=install-directory/sonar-scanner-vX.Y.Z.MMMM-macosx" output + grep "sonar-scanner-bin=install-directory/sonar-scanner-vX.Y.Z.MMMM-macosx/bin/sonar-scanner" output + + echo "- Check build-wrapper:" + grep "build-wrapper-url=http://sonar-host.com/static/cpp/build-wrapper-macosx-x86.zip" output + grep "build-wrapper-dir=install-directory/build-wrapper-macosx-x86" output + grep "build-wrapper-bin=install-directory/build-wrapper-macosx-x86/build-wrapper-macosx-x86" output + + - name: Unssuported OS + shell: bash + env: + OS: 'unsupportedOS' + ARCH: 'X64' + run: | + (./scripts/configure_paths.sh || echo "=== Script failed ===") > output + + echo "- Check errors:" + grep "::error::Unsupported runner OS 'unsupportedOS'" output + grep "=== Script failed ===" output + + - name: Unssuported architecture + shell: bash + env: + OS: 'Linux' + ARCH: 'X86' + run: | + (./scripts/configure_paths.sh || echo "=== Script failed ===") > output + + echo "- Check errors:" + grep "::error::Architecture 'X86' is unsupported by build-wrapper" output + grep "=== Script failed ===" output + + + download-script-test: + name: download.sh script test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Download test without validation + shell: bash + env: + INSTALL_PATH: 'install-directory-no-sha-validation' + DOWNLOAD_URL: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip' + EXPECTED_SHA: 'incorrect-sha-not-validated' + TMP_ZIP_PATH: ${{ runner.temp }}/sonar-scanner.zip + run: | + ./scripts/download.sh > output + test -f "$TMP_ZIP_PATH" + grep -v "::error::" output + - name: Download test with validation + shell: bash + env: + INSTALL_PATH: 'install-directory-sha-validation' + DOWNLOAD_URL: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip' + EXPECTED_SHA: '9411331814c1d002bd65d37758b872918b7602e7cf3ca5b83a3e19a729b2be05' + TMP_ZIP_PATH: ${{ runner.temp }}/sonar-scanner.zip + run: | + ./scripts/download.sh -v > output + test -f "$TMP_ZIP_PATH" + grep -v "::error::" output + - name: Incorrect install dir + shell: bash + env: + INSTALL_PATH: '' + run: | + (./scripts/download.sh || echo "=== Script failed ===") > output + grep "::error::Failed to create" output + grep "=== Script failed ===" output + - name: Incorrect download url + shell: bash + env: + INSTALL_PATH: 'install-directory-incorrect-url' + DOWNLOAD_URL: 'incorrect-url' + run: | + (./scripts/download.sh || echo "=== Script failed ===") > output + grep "::error::Failed to download 'incorrect-url'" output + grep "=== Script failed ===" output + - name: Incorrect SHA256 + shell: bash + env: + INSTALL_PATH: 'install-directory-incorrect-sha' + DOWNLOAD_URL: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip' + EXPECTED_SHA: 'incorrect-sha256' + TMP_ZIP_PATH: ${{ runner.temp }}/sonar-scanner.zip + run: | + (./scripts/download.sh -v || echo "=== Script failed ===") > output + grep "::error::Checking sha256 failed" output + grep "=== Script failed ===" output + - name: Mismatching SHA256 + shell: bash + env: + INSTALL_PATH: 'install-directory-mismtaching-sha' + DOWNLOAD_URL: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip' + EXPECTED_SHA: '3e121d85a4adb1f30b917d5f3eb897966b59e02c3d6d313a78dcd964193dc963' + TMP_ZIP_PATH: ${{ runner.temp }}/sonar-scanner.zip + run: | + (./scripts/download.sh -v || echo "=== Script failed ===") > output + grep "::error::Checking sha256 failed" output + grep "=== Script failed ===" output + + fetch-latest-version-test: + name: fetch_latest_version.sh script test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Test script + shell: bash + run: | + ./scripts/fetch_latest_version.sh > output + + echo "- Check sonar-scanner version:" + grep "sonar-scanner-version=" output + SONAR_SCANNER_VERSION=$(cat output | cut -d= -f 2) + test ! -z "${SONAR_SCANNER_VERSION}" + + echo "- Check windows sonar-scanner URLs:" + grep "sonar-scanner-url-windows=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-windows.zip" output + grep -e "^sonar-scanner-sha-windows=[0-9A-Fa-f]\+$" output + + echo "- Check linux sonar-scanner URLs:" + grep "sonar-scanner-url-linux=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux.zip" output + grep -e "^sonar-scanner-sha-linux=[0-9A-Fa-f]\+$" output + + echo "- Check macosx sonar-scanner URLs:" + grep "sonar-scanner-url-macosx=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-macosx.zip" output + grep -e "^sonar-scanner-sha-macosx=[0-9A-Fa-f]\+$" output + + output-test: + name: Test action outputs + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + cache: [true, false] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Run SonarQube C/C++ action + id: run-action + uses: ./ + env: + SONAR_HOST_URL: 'https://next.sonarqube.com/' + with: + cache-binaries: ${{ matrix.cache }} + + - name: SONAR_HOST_URL is set + shell: bash + run: | + [[ $SONAR_HOST_URL == "https://next.sonarqube.com/" ]] + + - name: sonar-scanner is installed and in PATH + run: | + sonar-scanner --help | grep "INFO: usage: sonar-scanner " + + - name: sonar-scanner-binary output is correct + shell: bash + env: + BINARY: ${{ steps.run-action.outputs.sonar-scanner-binary }} + run: | + "$BINARY" --help | grep "INFO: usage: sonar-scanner " + + # build-wrapper does not have --help or equivalent option. + # Pass to few arguments and ignore error code + - name: build-wrapper is installed and in PATH on Windows + if: runner.os == 'Windows' + shell: bash + run: | + (build-wrapper-win-x86-64.exe || true) | grep "build-wrapper, version " + + - name: build-wrapper is installed and in PATH on Linux + if: runner.os == 'Linux' + shell: bash + run: | + (build-wrapper-linux-x86-64 || true) | grep "build-wrapper, version " + + - name: build-wrapper is installed and in PATH on macOS + if: runner.os == 'macOs' + shell: bash + run: | + (build-wrapper-macosx-x86 || true) | grep "build-wrapper, version " + + - name: build-wrapper-binary output is correct + shell: bash + env: + BINARY: ${{ steps.run-action.outputs.build-wrapper-binary }} + run: | + ("$BINARY" || true) | grep "build-wrapper, version " diff --git a/.github/workflows/version_update.yml b/.github/workflows/version_update.yml new file mode 100644 index 0000000..6e9b43c --- /dev/null +++ b/.github/workflows/version_update.yml @@ -0,0 +1,50 @@ +name: sonar-scanner version check +on: + schedule: + - cron: '15 10 * * *' + +jobs: + update-version: + name: Prepare pull request for sonar-scanner version update + runs-on: ubuntu-latest + steps: + - run: sudo apt install -y jq + + - uses: actions/checkout@v4 + with: + ref: main + persist-credentials: true + fetch-depth: 0 + + - name: "Fetch currently used sonar-scanner version" + id: tagged-version + shell: bash + run: cat sonar-scanner-version >> $GITHUB_OUTPUT + + - name: "Fetch lastest sonar-scanner version" + id: latest-version + shell: bash + run: | + ./scripts/fetch_latest_version.sh > sonar-scanner-version + cat sonar-scanner-version >> $GITHUB_OUTPUT + + - name: "Create Pull Request for version update" + if: steps.tagged-version.outputs.sonar-scanner-version != steps.latest-version.outputs.sonar-scanner-version + shell: bash + env: + UPDATE_BRANCH: update-to-sonar-scanner-${{ steps.latest-version.outputs.sonar-scanner-version }} + TITLE: "Update sonar-scanner-version to ${{ steps.latest-version.outputs.sonar-scanner-version }}" + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config --global user.name "SonarTech" + git config --global user.email "sonartech@sonarsource.com" + git checkout -b ${UPDATE_BRANCH} + git add sonar-scanner-version + git commit -m "${TITLE}" + git push --force-with-lease origin ${UPDATE_BRANCH} + gh pr list + + if [[ $(gh pr list -H "${UPDATE_BRANCH}" | grep "${UPDATE_BRANCH}" | wc -l) -eq 0 ]]; then + gh pr create -B main -H ${UPDATE_BRANCH} --title "${TITLE}" --body "Automatic updated of sonar-scanner version value. Needs to be tagged for release." + fi + diff --git a/README.md b/README.md index a0e6490..0d75814 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,125 @@ -# sonarqube-github-c-cpp -Integrate SonarQube code analysis to GitHub Actions when build-wrapper or relative paths support is required. Use https://github.com/SonarSource/sonarqube-scan-action otherwise. +# Scan your code with SonarQube [![Tests](https://github.com/SonarSource/sonarqube-github-c-cpp/actions/workflows/tests.yml/badge.svg)](https://github.com/SonarSource/sonarqube-github-c-cpp/actions/workflows/tests.yml) + +Using this GitHub Action, achieve [Clean Code](https://www.sonarsource.com/solutions/clean-code/?utm_medium=referral&utm_source=github&utm_campaign=clean-code&utm_content=sonarqube-scan-action) +with [SonarQube](https://www.sonarqube.org/) by scanning to detect Bugs, Vulnerabilities, and Code Smells in C, C++ and Objective-C! + +The SonarQube logo + +SonarQube is the leading product for Continuous Code Quality and code Security. +It supports most popular programming languages, including Java, JavaScript, TypeScript, C#, Python, C, C++, and many more. + +## Requirements + +To run an analysis on your code, you first need to set up your project on SonarQube. +Your SonarQube instance must be accessible from GitHub, and you will need a Project analysis token or a Global analysis token to run the analysis (more information below under **Environment variables**). + +Read more information on how to analyze your code [here](https://docs.sonarqube.org/latest/analysis/github-integration/). + + +## Usage + + +Project metadata, including the location to the sources to be analyzed, must be declared in the file `sonar-project.properties` in the base directory: + +```properties +sonar.projectKey= + +# relative paths to source directories. More details and properties are described +# in https://docs.sonarsource.com/sonarqube/latest/project-administration/analysis-scope/ +sonar.sources=. +``` + +The workflow, usually declared in `.github/workflows/build.yml`, looks like: + +```yaml +on: + # Trigger analysis when pushing in master or pull requests, and when creating + # a pull request. + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened] +name: Main Workflow +jobs: + sonarqube: + runs-on: ubuntu-latest + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + steps: + - uses: actions/checkout@v4 + with: + # Disabling shallow clone is recommended for improving relevancy of reporting + fetch-depth: 0 + - name: Install sonar-scanner and build-wrapper + uses: sonarsource/sonarqube-github-c-cpp@v1 + env: + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }} + - name: Run build-wrapper + run: | + #here goes your compilation wrapped with build-wrapper; See https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/languages/c-family/#using-build-wrapper for more information + # build-preparation steps + # build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} build-command + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + run: sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" #Consult https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options +``` + +You can change the `build-wrapper` and `sonar-scanner` installation path by using the optional input `installation-path` like this: + +```yaml +uses: sonarsource/sonarqube-github-c-cpp@v1 +with: + installation-path: my/custom/directory/path +``` +Also, the absolute paths to the installed build-wrapper and sonar-scanner binaries are returned as outputs from the action. + +Moreover, by default the action will cache sonar-scanner installation. However, you can disable caching by using the optional input: `cache-binaries` like this: +```yaml +uses: sonarsource/sonarqube-github-c-cpp@v1 +with: + cache-binaries: false +``` + +If your SonarQube server uses a self-signed certificate, you can pass a root certificate (in PEM format) to the java certificate store: + +```yaml +uses: sonarsource/sonarqube-github-c-cpp@v1 +env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }} +``` + +See also [example configurations](https://github.com/sonarsource-cfamily-examples?q=gh-actions-sc&type=all&language=&sort=) + +### Secrets and environment variables + +Following secrets are required for successful invocation of sonar-scanner: +- `SONAR_TOKEN` – **Required** this is the token used to authenticate access to SonarQube. You can read more about security tokens [here](https://docs.sonarqube.org/latest/user-guide/user-token/). You can set the `SONAR_TOKEN` environment variable in the "Secrets" settings page of your repository, or you can add them at the level of your GitHub organization (recommended). +- *`GITHUB_TOKEN` – Provided by Github (see [Authenticating with the GITHUB_TOKEN](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token)).* + +Environment variables: +- `SONAR_HOST_URL` – **Required** this tells the scanner where SonarQube is hosted. You can set the `SONAR_HOST_URL` environment variable in the "Secrets" settings page of your repository, or you can add them at the level of your GitHub organization (recommended). +- `SONAR_ROOT_CERT` – Holds an additional root certificate (in PEM format) that is used to validate the SonarQube server certificate. You can set the `SONAR_ROOT_CERT` environment variable in the "Secrets" settings page of your repository, or you can add them at the level of your GitHub organization (recommended). + +## Do not use this GitHub action if you are in the following situations + +* You want to analyze code written in a language other than C, C++ or Objective-C?. Use the [SonarQube Scan GitHub Action](https://github.com/SonarSource/sonarqube-scan-action) instead +* You want to run the action on a 32-bits system - build wrappers support only 64-bits OS + +## Additional information + +This action installs `coreutils` if run on macOS + +## Have question or feedback? + +To provide feedback (requesting a feature or reporting a bug) please post on the [SonarSource Community Forum](https://community.sonarsource.com/) with the tag `sonarqube`. + +## License + +The action file and associated scripts and documentation in this project are released under the LGPLv3 License. diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..27c7b7b --- /dev/null +++ b/action.yml @@ -0,0 +1,123 @@ +name: 'SonarQube Scan for C and C++' +description: 'Scan your C and C++ code with SonarQube to detect bugs, vulnerabilities and code smells.' +branding: + icon: check + color: green +inputs: + installation-path: + description: 'Directory where the sonar-scanner and build wrapper will be installed. Created if does not exists.' + required: false + default: '.sonar' + cache-binaries: + description: 'Controls if installed binaries are cached using GitHub cache.' + required: false + default: 'true' + +outputs: + sonar-scanner-binary: + description: "Absolute path to sonar-scanner binary." + value: ${{ steps.setup-outputs.outputs.sonar-scanner-binary }} + build-wrapper-binary: + description: "Absolute path to build-wrapper binary." + value: ${{ steps.setup-outputs.outputs.build-wrapper-binary }} + +runs: + using: "composite" + steps: + # install packaged required for greadlink and sha256sum command on macOS + - name: Install required packages for macOS + if: runner.os == 'macOS' + shell: bash + run: brew install coreutils + + - name: Verify and create installation path + shell: bash + env: + INSTALL_PATH: ${{ inputs.installation-path }} + run: ${GITHUB_ACTION_PATH}/scripts/create_install_path.sh + + - name: Set version of sonar-scanner + id: sonar-scanner-version + shell: bash + run: cat ${GITHUB_ACTION_PATH}/sonar-scanner-version >> $GITHUB_OUTPUT + + - name: Configure paths + id: configure_paths + shell: bash + env: + OS: ${{ runner.os }} + ARCH: ${{ runner.arch }} + INSTALL_PATH: ${{ inputs.installation-path }} + SONAR_SCANNER_VERSION: ${{ steps.sonar-scanner-version.outputs.sonar-scanner-version }} + SONAR_SCANNER_URL_WINDOWS: ${{ steps.sonar-scanner-version.outputs.sonar-scanner-url-windows }} + SONAR_SCANNER_SHA_WINDOWS: ${{ steps.sonar-scanner-version.outputs.sonar-scanner-sha-windows }} + SONAR_SCANNER_URL_LINUX: ${{ steps.sonar-scanner-version.outputs.sonar-scanner-url-linux }} + SONAR_SCANNER_SHA_LINUX: ${{ steps.sonar-scanner-version.outputs.sonar-scanner-sha-linux }} + SONAR_SCANNER_URL_MACOSX: ${{ steps.sonar-scanner-version.outputs.sonar-scanner-url-macosx }} + SONAR_SCANNER_SHA_MACOSX: ${{ steps.sonar-scanner-version.outputs.sonar-scanner-sha-macosx }} + run: ${GITHUB_ACTION_PATH}/scripts/configure_paths.sh >> $GITHUB_OUTPUT + + - name: Cache sonar-scanner installation + id: cache-sonar-tools + if: inputs.cache-binaries == 'true' + uses: actions/cache@v3 + env: + # The default value is 60mins. Reaching timeout is treated the same as a cache miss. + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + with: + key: sonar-scanner-${{ runner.os }}-${{ steps.sonar-scanner-version.outputs.sonar-scanner-version }} + path: ${{ steps.configure_paths.outputs.sonar-scanner-dir }} + + - name: Download and install sonar-scanner + if: steps.cache-sonar-tools.outputs.cache-hit != 'true' + shell: bash + env: + DOWNLOAD_URL: ${{ steps.configure_paths.outputs.sonar-scanner-url }} + EXPECTED_SHA: ${{ steps.configure_paths.outputs.sonar-scanner-sha }} + INSTALL_PATH: ${{ inputs.installation-path }} + TMP_ZIP_PATH: ${{ runner.temp }}/sonar-scanner.zip + run: ${GITHUB_ACTION_PATH}/scripts/download.sh -v + + - name: Add the custom root certificate to java certificate store + shell: bash + run: ${GITHUB_ACTION_PATH}/scripts/cert.sh + + - name: Download and install build-wrapper + shell: bash + env: + DOWNLOAD_URL: ${{ steps.configure_paths.outputs.build-wrapper-url }} + INSTALL_PATH: ${{ inputs.installation-path }} + TMP_ZIP_PATH: ${{ runner.temp }}/build-wrapper.zip + run: ${GITHUB_ACTION_PATH}/scripts/download.sh + + - name: Setup action outputs + id: setup-outputs + shell: bash + env: + SONAR_SCANNER_DIR: ${{ steps.configure_paths.outputs.sonar-scanner-dir }} + SONAR_SCANNER_BIN: ${{ steps.configure_paths.outputs.sonar-scanner-bin }} + BUILD_WRAPPER_DIR: ${{ steps.configure_paths.outputs.build-wrapper-dir }} + BUILD_WRAPPER_BIN: ${{ steps.configure_paths.outputs.build-wrapper-bin }} + run: | + source ${GITHUB_ACTION_PATH}/scripts/utils.sh + + echo "::group::Action outputs" + echo "SONAR_HOST_URL=${SONAR_HOST_URL}" >> $GITHUB_ENV + echo "'SONAR_HOST_URL' environment variable set to '${SONAR_HOST_URL}'" + + SONAR_SCANNER_BIN_DIR=$(realpath "${SONAR_SCANNER_DIR}/bin") + echo "${SONAR_SCANNER_BIN_DIR}" >> $GITHUB_PATH + echo "'${SONAR_SCANNER_BIN_DIR}' added to the path" + + SONAR_SCANNER_BIN=$(realpath "${SONAR_SCANNER_BIN}") + echo "sonar-scanner-binary=${SONAR_SCANNER_BIN}" >> $GITHUB_OUTPUT + echo "'sonar-scanner-binary' output set to '${SONAR_SCANNER_BIN}'" + + BUILD_WRAPPER_BIN_DIR=$(realpath "${BUILD_WRAPPER_DIR}") + echo "${BUILD_WRAPPER_BIN_DIR}" >> $GITHUB_PATH + echo "'${BUILD_WRAPPER_BIN_DIR}' added to the path" + + BUILD_WRAPPER_BIN=$(realpath "${BUILD_WRAPPER_BIN}") + echo "build-wrapper-binary=${BUILD_WRAPPER_BIN}" >> $GITHUB_OUTPUT + echo "'build-wrapper-binary' output set to '${BUILD_WRAPPER_BIN}'" + echo "::endgroup::" diff --git a/images/SonarQube-72px.png b/images/SonarQube-72px.png new file mode 100644 index 0000000..400830b Binary files /dev/null and b/images/SonarQube-72px.png differ diff --git a/scripts/cert.sh b/scripts/cert.sh new file mode 100755 index 0000000..2c2a2a5 --- /dev/null +++ b/scripts/cert.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [[ -n "${SONAR_ROOT_CERT}" ]]; then + echo "Adding custom root certificate to java certificate store" + rm -f /tmp/tmpcert.pem + echo "${SONAR_ROOT_CERT}" > /tmp/tmpcert.pem + keytool -keystore /etc/ssl/certs/java/cacerts -storepass changeit -noprompt -trustcacerts -importcert -alias sonarqube -file /tmp/tmpcert.pem +fi diff --git a/scripts/configure_paths.sh b/scripts/configure_paths.sh new file mode 100755 index 0000000..8a8ed2b --- /dev/null +++ b/scripts/configure_paths.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +if [[ ${ARCH} != "X64" ]]; then + echo "::error::Architecture '${ARCH}' is unsupported by build-wrapper" + exit 1 +fi + +case ${OS} in + Windows) + SONAR_SCANNER_SUFFIX="windows" + BUILD_WRAPPER_SUFFIX="win-x86" + SONAR_SCANNER_NAME="sonar-scanner.bat" + BUILD_WRAPPER_NAME="build-wrapper-win-x86-64.exe" + SONAR_SCANNER_URL="${SONAR_SCANNER_URL_WINDOWS}" + SONAR_SCANNER_SHA="${SONAR_SCANNER_SHA_WINDOWS}" + ;; + Linux) + SONAR_SCANNER_SUFFIX="linux" + BUILD_WRAPPER_SUFFIX="linux-x86" + SONAR_SCANNER_NAME="sonar-scanner" + BUILD_WRAPPER_NAME="build-wrapper-linux-x86-64" + SONAR_SCANNER_URL="${SONAR_SCANNER_URL_LINUX}" + SONAR_SCANNER_SHA="${SONAR_SCANNER_SHA_LINUX}" + ;; + macOS) + SONAR_SCANNER_SUFFIX="macosx" + BUILD_WRAPPER_SUFFIX="macosx-x86" + SONAR_SCANNER_NAME="sonar-scanner" + BUILD_WRAPPER_NAME="build-wrapper-macosx-x86" + SONAR_SCANNER_URL="${SONAR_SCANNER_URL_MACOSX}" + SONAR_SCANNER_SHA="${SONAR_SCANNER_SHA_MACOSX}" + ;; + *) + echo "::error::Unsupported runner OS '${OS}'" + exit 1 + ;; +esac + + +echo "sonar-scanner-url=${SONAR_SCANNER_URL}" +echo "sonar-scanner-sha=${SONAR_SCANNER_SHA}" + +SONAR_SCANNER_DIR="${INSTALL_PATH}/sonar-scanner-${SONAR_SCANNER_VERSION}-${SONAR_SCANNER_SUFFIX}" +echo "sonar-scanner-dir=${SONAR_SCANNER_DIR}" +echo "sonar-scanner-bin=${SONAR_SCANNER_DIR}/bin/${SONAR_SCANNER_NAME}" + +BUILD_WRAPPER_DIR="${INSTALL_PATH}/build-wrapper-${BUILD_WRAPPER_SUFFIX}" +echo "build-wrapper-url=${SONAR_HOST_URL}/static/cpp/build-wrapper-${BUILD_WRAPPER_SUFFIX}.zip" +echo "build-wrapper-dir=${BUILD_WRAPPER_DIR}" +echo "build-wrapper-bin=${BUILD_WRAPPER_DIR}/${BUILD_WRAPPER_NAME}" + diff --git a/scripts/create_install_path.sh b/scripts/create_install_path.sh new file mode 100755 index 0000000..6c65831 --- /dev/null +++ b/scripts/create_install_path.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +source "$(dirname -- "$0")/utils.sh" + +echo "Installation path is '${INSTALL_PATH}'" + +test ! -z "${INSTALL_PATH}" +check_status "Empty installation path specified" + +if [[ ! -e "${INSTALL_PATH}" ]]; then + mkdir -p "${INSTALL_PATH}" + check_status "Failed to create non-existing installation path '${INSTALL_PATH}'" +fi + +ABSOLUTE_INSTALL_PATH=$(realpath "${INSTALL_PATH}") +echo "Absolute installation path is '${ABSOLUTE_INSTALL_PATH}'" + +test -d ${INSTALL_PATH} +check_status "Installation path '${INSTALL_PATH}' is not a directory (absolute path is '${ABSOLUTE_INSTALL_PATH}')" + +test -r "${INSTALL_PATH}" +check_status "Installation path '${INSTALL_PATH}' is not readable (absolute path is '${ABSOLUTE_INSTALL_PATH}')" + +test -w "${INSTALL_PATH}" +check_status "Installation path '${INSTALL_PATH}' is not writeable (absolute path is '${ABSOLUTE_INSTALL_PATH}')" + diff --git a/scripts/download.sh b/scripts/download.sh new file mode 100755 index 0000000..9e1aefa --- /dev/null +++ b/scripts/download.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +source "$(dirname -- "$0")/utils.sh" + +VERIFY_CORRECTNESS=false + +help() { + cat <