From 94d4f8ac4aaefccd7fb84bff00b0aeb2d65fcd49 Mon Sep 17 00:00:00 2001 From: Antonio Aversa Date: Tue, 12 Nov 2024 14:16:39 +0100 Subject: [PATCH] SQSCANGHA-46 Replace the Docker action by a composite action --- .cirrus.star | 4 --- .cirrus.yml | 37 ---------------------------- .github/workflows/qa.yml | 41 ++++++++++++++++++++++--------- Dockerfile | 21 ---------------- README.md | 15 ------------ action.yml | 38 ++++++++++++++++++++++++----- cleanup.sh | 13 ---------- entrypoint.sh | 47 ------------------------------------ install-sonar-scanner-cli.sh | 34 ++++++++++++++++++++++++++ run-sonar-scanner.sh | 41 +++++++++++++++++++++++++++++++ sanity-checks.sh | 18 ++++++++++++++ 11 files changed, 155 insertions(+), 154 deletions(-) delete mode 100644 .cirrus.star delete mode 100644 .cirrus.yml delete mode 100644 Dockerfile delete mode 100755 cleanup.sh delete mode 100755 entrypoint.sh create mode 100755 install-sonar-scanner-cli.sh create mode 100755 run-sonar-scanner.sh create mode 100755 sanity-checks.sh diff --git a/.cirrus.star b/.cirrus.star deleted file mode 100644 index 9f91e15..0000000 --- a/.cirrus.star +++ /dev/null @@ -1,4 +0,0 @@ -load("github.com/SonarSource/cirrus-modules@v3", "load_features") - -def main(ctx): - return load_features(ctx) diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 97cdd3a..0000000 --- a/.cirrus.yml +++ /dev/null @@ -1,37 +0,0 @@ -env: - CIRRUS_VAULT_URL: https://vault.sonar.build:8200 - CIRRUS_VAULT_AUTH_PATH: jwt-cirrusci - CIRRUS_VAULT_ROLE: cirrusci-${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME} - - # Mend scan global configuration - MEND_API_KEY: VAULT[development/kv/data/mend data.apikey] - - # Staging image configuration - STAGING_IMAGE_NAME: sonarsource/sonarqube-scan-action - CURRENT_TAG: master - -vm_instance_template: &VM_TEMPLATE - experimental: true # see https://github.com/cirruslabs/cirrus-ci-docs/issues/1051 - image: docker-builder-v* - type: t2.small - region: eu-central-1 - disk: 10 - cpu: 4 - memory: 16G - -mend_task: - ec2_instance: - <<: *VM_TEMPLATE - # run only on master and long-term branches - only_if: $CIRRUS_USER_COLLABORATOR == 'true' && ($CIRRUS_BRANCH == "master" || $CIRRUS_BRANCH =~ "branch-.*") - setup_script: - - docker build --tag "${STAGING_IMAGE_NAME}:${CURRENT_TAG}" . - - apt-get remove -y unattended-upgrades - - apt-get update && apt-get install -y --no-install-recommends openjdk-17-jre - - curl -sSL https://unified-agent.s3.amazonaws.com/wss-unified-agent.jar -o wss-unified-agent.jar - - echo "docker.includes=${CURRENT_TAG}" >> .cirrus/wss-unified-agent.config - scan_script: - - echo "Scan the ${STAGING_IMAGE_NAME}:${CURRENT_TAG} image" - - java -jar wss-unified-agent.jar -c .cirrus/wss-unified-agent.config -apiKey $MEND_API_KEY - - diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index f2be5a2..f4bd70c 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -27,7 +27,10 @@ jobs: argsInputTest: name: > 'args' input - runs-on: ubuntu-latest + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: @@ -35,7 +38,7 @@ jobs: - name: Run action with args uses: ./ with: - args: -Dsonar.someArg=aValue + args: -Dsonar.someArg=aValue -Dsonar.scanner.internal.dumpToFile=./output.properties env: SONAR_HOST_URL: http://not_actually_used SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}' @@ -45,7 +48,10 @@ jobs: projectBaseDirInputTest: name: > 'projectBaseDir' input - runs-on: ubuntu-latest + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: @@ -54,6 +60,7 @@ jobs: - name: Run action with projectBaseDir uses: ./ with: + args: -Dsonar.scanner.internal.dumpToFile=./output.properties projectBaseDir: ./baseDir env: SONAR_HOST_URL: http://not_actually_used @@ -78,6 +85,7 @@ jobs: SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}' with: projectBaseDir: ./test/gradle-project + args: -Dsonar.scanner.internal.dumpToFile=./output.properties - name: Assert run: | ./test/assertFileExists ./output.properties @@ -98,6 +106,7 @@ jobs: SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}' with: projectBaseDir: ./test/gradle-project + args: -Dsonar.scanner.internal.dumpToFile=./output.properties - name: Assert run: | ./test/assertFileExists ./output.properties @@ -118,6 +127,7 @@ jobs: SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}' with: projectBaseDir: ./test/maven-project + args: -Dsonar.scanner.internal.dumpToFile=./output.properties - name: Assert run: | ./test/assertFileExists ./output.properties @@ -145,7 +155,7 @@ jobs: id: runTest uses: ./ env: - SONAR_HOST_URL: http://sonarqube:9000 + SONAR_HOST_URL: http://localhost:9000 with: args: -Dsonar.login=admin -Dsonar.password=admin projectBaseDir: ./test/example-project @@ -155,13 +165,18 @@ jobs: runnerDebugUsedTest: name: > 'RUNNER_DEBUG' is used - runs-on: ubuntu-latest + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Run action with debug mode uses: ./ + with: + args: -Dsonar.scanner.internal.dumpToFile=./output.properties env: RUNNER_DEBUG: 1 SONAR_HOST_URL: http://not_actually_used @@ -193,29 +208,34 @@ jobs: uses: actions/cache@v4 with: path: ${{ github.workspace }}/.sonar/cache - key: ${{ runner.os }}-sonar + key: ${{ runner.os }}-${{ runner.arch }}-sonar - name: Run action on sample project id: runTest uses: ./ env: - SONAR_HOST_URL: http://sonarqube:9000 + SONAR_HOST_URL: http://localhost:9000 SONAR_USER_HOME: ${{ github.workspace }}/.sonar with: args: -Dsonar.login=admin -Dsonar.password=admin projectBaseDir: ./test/example-project - name: Assert run: | - ./test/assertFileExists ./test/example-project/.scannerwork/report-task.txt + ./test/assertFileExists ./test/example-project/.scannerwork/report-task.txt useSslCertificate: name: > 'SONAR_ROOT_CERT' is converted to truststore - runs-on: ubuntu-latest + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Run action with SSL certificate uses: ./ + with: + args: -Dsonar.scanner.internal.dumpToFile=./output.properties env: SONAR_ROOT_CERT: | -----BEGIN CERTIFICATE----- @@ -252,7 +272,6 @@ jobs: Fct6d1S08JAosVnZcP2P7Yz+TbmDRtsqCgk= -----END CERTIFICATE----- SONAR_HOST_URL: http://not_actually_used - SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}' - name: Assert run: | - ./test/assertFileContains ./output.properties "sonar.scanner.truststorePassword=changeit" + ./test/assertFileExists ~/.sonar/ssl/truststore.p12 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index dd81624..0000000 --- a/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM sonarsource/sonar-scanner-cli:11.1 - -LABEL version="3.1.0" \ - repository="https://github.com/sonarsource/sonarqube-scan-action" \ - homepage="https://github.com/sonarsource/sonarqube-scan-action" \ - maintainer="SonarSource" \ - com.github.actions.name="SonarQube Scan" \ - com.github.actions.description="Scan your code with SonarQube to detect Bugs, Vulnerabilities and Code Smells in up to 27 programming languages!" \ - com.github.actions.icon="check" \ - com.github.actions.color="green" - -# GitHub actions should be run under ROOT -# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#docker-container-filesystem -USER 0 - -COPY entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh -COPY cleanup.sh /cleanup.sh -RUN chmod +x /cleanup.sh - -ENTRYPOINT ["/entrypoint.sh"] diff --git a/README.md b/README.md index edc6836..1d83d6d 100644 --- a/README.md +++ b/README.md @@ -118,25 +118,10 @@ This GitHub Action will not work for all technologies. If you are in one of the * You want to analyze a .NET solution. Read the documentation about our [Scanner for .NET](https://redirect.sonarsource.com/doc/install-configure-scanner-msbuild.html). * You want to analyze C or C++ code. Starting from SonarQube 10.6, this GitHub Action will scan C and C++ out of the box. If you want to have better control over the scan configuration/setup, you can switch to the [SonarQube C and C++](https://github.com/SonarSource/sonarqube-github-c-cpp) GitHub Action. -## Error cleaning up workspace - -In some cases, the checkout action may fail to clean up the workspace. This is a known problem for GitHub actions implemented as a docker container (such as `sonarqube-scan-action`) when self-hosted runners are used. -Example of the error message: `File was unable to be removed Error: EACCES: permission denied, unlink '/actions-runner/_work//project/.scannerwork/.sonar_lock'` -To work around the problem, `sonarqube-scan-action` attempts to fix the permission of the temporary files that it creates. If that doesn't work, you can manually clean up the workspace by running the following action: -``` -- name: Clean the workspace - uses: docker://alpine - with: - args: /bin/sh -c "find \"${GITHUB_WORKSPACE}\" -mindepth 1 ! -name . -prune -exec rm -rf {} +" -``` -You can find more info [here](https://github.com/actions/runner/issues/434). - ## Have questions or feedback? To provide feedback (requesting a feature or reporting a bug) please post on the [SonarSource Community Forum](https://community.sonarsource.com/tags/c/help/sq/github-actions). ## License -The Dockerfile and associated scripts and documentation in this project are released under the LGPLv3 License. - Container images built with this project include third-party materials. diff --git a/action.yml b/action.yml index b2baff6..14854e5 100644 --- a/action.yml +++ b/action.yml @@ -4,11 +4,6 @@ description: > branding: icon: check color: green -runs: - using: docker - image: Dockerfile - entrypoint: "/entrypoint.sh" - post-entrypoint: "/cleanup.sh" inputs: args: description: Additional arguments to the sonar-scanner @@ -16,4 +11,35 @@ inputs: projectBaseDir: description: Set the sonar.projectBaseDir analysis property required: false - default: . + scannerVersion: + description: Version of the Sonar Scanner CLI to use + required: false + default: 6.2.1.4610 +runs: + using: "composite" + steps: + - name: Sanity checks + run: ${GITHUB_ACTION_PATH}/sanity-checks.sh + shell: bash + env: + INPUT_PROJECTBASEDIR: ${{ inputs.projectBaseDir }} + - name: Load Sonar Scanner CLI from cache + id: sonar-scanner-cli + uses: actions/cache@v4.0.2 + with: + path: ${{ runner.temp }}/sonar-scanner-cli-${{ inputs.scannerVersion }}-${{ runner.os }}-${{ runner.arch }} + key: sonar-scanner-cli-${{ inputs.scannerVersion }}-${{ runner.os }}-${{ runner.arch }} + - name: Install Sonar Scanner CLI + if: steps.sonar-scanner-cli.outputs.cache-hit != 'true' + run: ${GITHUB_ACTION_PATH}/install-sonar-scanner-cli.sh + shell: bash + env: + INPUT_SCANNERVERSION: ${{ inputs.scannerVersion }} + - name: Add SonarScanner CLI to the PATH + run: echo "${RUNNER_TEMP}/sonar-scanner-cli-${{ inputs.scannerVersion }}-${{ runner.os }}-${{ runner.arch }}/bin" >> $GITHUB_PATH + shell: bash + - name: Run SonarScanner + run: ${GITHUB_ACTION_PATH}/run-sonar-scanner.sh ${{ inputs.args }} + shell: bash + env: + INPUT_PROJECTBASEDIR: ${{ inputs.projectBaseDir }} \ No newline at end of file diff --git a/cleanup.sh b/cleanup.sh deleted file mode 100755 index bdc3316..0000000 --- a/cleanup.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -e - -# Reset all files permissions to the default Runner user and group to allow the follow up steps (mainly cache) to access all files. - -# Assume that the first (non-hidden) file in the project directory is one from the project, and not one written by the scanner -_tmp_file=$(ls "${INPUT_PROJECTBASEDIR%/}/" | head -1) -echo "Reading permissions from $_tmp_file" -PERM=$(stat -c "%u:%g" "${INPUT_PROJECTBASEDIR%/}/$_tmp_file") - -echo "Applying permissions $PERM to all files in the project base directory" -chown -R "$PERM" "${INPUT_PROJECTBASEDIR%/}/" diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index d40ba60..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -set -eo pipefail - -echo "::warning title=Docker removed in the next major version::Users on the master branch of this GitHub action will be upgraded automatically on December 9th to its next major version, which replaces Docker with a composite action, executing in the runner environment. Self-hosted runners analyzing JS/TS code against SonarQube 10.2 and below will need to have Node JS installed." - -declare -a args=() - -if [[ -z "${SONAR_TOKEN}" ]]; then - echo "============================ WARNING ============================" - echo "Running this GitHub Action without SONAR_TOKEN is not recommended" - echo "============================ WARNING ============================" -fi - -if [[ -n "${SONAR_ROOT_CERT}" ]]; then - echo "Adding custom root certificate to the scanner truststore" - rm -f /tmp/tmpcert.pem - echo "${SONAR_ROOT_CERT}" > /tmp/tmpcert.pem - # we can't use the default "sonar" password as keytool requires a password with at least 6 characters - args+=("-Dsonar.scanner.truststorePassword=changeit") - mkdir -p $SONAR_USER_HOME/ssl - keytool -storetype PKCS12 -keystore $SONAR_USER_HOME/ssl/truststore.p12 -storepass changeit -noprompt -trustcacerts -importcert -alias sonarqube -file /tmp/tmpcert.pem - # for older SQ versions < 10.6 - export SONAR_SCANNER_OPTS="${SONAR_SCANNER_OPTS:-} -Djavax.net.ssl.trustStore=$SONAR_USER_HOME/ssl/truststore.p12 -Djavax.net.ssl.trustStorePassword=changeit" -fi - -if [[ -f "${INPUT_PROJECTBASEDIR%/}/pom.xml" ]]; then - echo "WARNING! Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action - to get more accurate results." -fi - -if [[ -f "${INPUT_PROJECTBASEDIR%/}/build.gradle" || -f "${INPUT_PROJECTBASEDIR%/}/build.gradle.kts" ]]; then - echo "WARNING! Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action - to get more accurate results." -fi - - -if [[ "$RUNNER_DEBUG" == '1' ]]; then - args+=("--debug") -fi - -unset JAVA_HOME - -args+=("-Dsonar.projectBaseDir=${INPUT_PROJECTBASEDIR}") - -sonar-scanner "${args[@]}" ${INPUT_ARGS} - diff --git a/install-sonar-scanner-cli.sh b/install-sonar-scanner-cli.sh new file mode 100755 index 0000000..7509d74 --- /dev/null +++ b/install-sonar-scanner-cli.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +set -eou pipefail + +#See https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables + +WGET=wget +if [[ "$RUNNER_OS" == "Linux" && "$RUNNER_ARCH" == "X64" ]]; then + FLAVOR="linux-x64" +elif [[ "$RUNNER_OS" == "Linux" && "$RUNNER_ARCH" == "ARM64" ]]; then + FLAVOR="linux-aarch64" +elif [[ "$RUNNER_OS" == "Windows" && "$RUNNER_ARCH" == "X64" ]]; then + FLAVOR="windows-x64" + WGET="C:\\msys64\\usr\\bin\\wget.exe" +elif [[ "$RUNNER_OS" == "macOS" && "$RUNNER_ARCH" == "X64" ]]; then + FLAVOR="macosx-x64" +elif [[ "$RUNNER_OS" == "macOS" && "$RUNNER_ARCH" == "ARM64" ]]; then + FLAVOR="macosx-aarch64" +else + echo "$RUNNER_OS $RUNNER_ARCH not supported" + exit 1 +fi + +set -x + +mkdir -p $RUNNER_TEMP/sonarscanner +cd $RUNNER_TEMP/sonarscanner + +$WGET --no-verbose --user-agent="sonarqube-scan-action" https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$INPUT_SCANNERVERSION-$FLAVOR.zip + +unzip -q sonar-scanner-cli-$INPUT_SCANNERVERSION-$FLAVOR.zip + +# Folder name should correspond to the directory cached by the actions/cache +mv sonar-scanner-$INPUT_SCANNERVERSION-$FLAVOR $RUNNER_TEMP/sonar-scanner-cli-$INPUT_SCANNERVERSION-$RUNNER_OS-$RUNNER_ARCH diff --git a/run-sonar-scanner.sh b/run-sonar-scanner.sh new file mode 100755 index 0000000..13c2f69 --- /dev/null +++ b/run-sonar-scanner.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -eo pipefail + +if [[ "$RUNNER_OS" == "Windows" ]]; then + SCANNER_BIN="sonar-scanner.bat" +else + SCANNER_BIN="sonar-scanner" +fi + +scanner_args=() +if [[ ${SONARCLOUD_URL} ]]; then + scanner_args+=("-Dsonar.scanner.sonarcloudUrl=${SONARCLOUD_URL}") +fi + +if [[ "$RUNNER_DEBUG" == '1' ]]; then + scanner_args+=('--debug') +fi + +if [[ -n "${INPUT_PROJECTBASEDIR}" ]]; then + scanner_args+=("-Dsonar.projectBaseDir=${INPUT_PROJECTBASEDIR}") +fi + +if [[ -n "${SONAR_ROOT_CERT}" ]]; then + echo "Adding SSL certificate to the Scanner truststore" + rm -f $RUNNER_TEMP/tmpcert.pem + echo "${SONAR_ROOT_CERT}" > $RUNNER_TEMP/tmpcert.pem + # Use keytool for now, as SonarQube 11.6 won't support openssl generated keystores + # keytool require a password > 6 characters, so we wan't use the default password 'sonar' + store_pass=changeit + mkdir -p ~/.sonar/ssl + keytool -storetype PKCS12 -keystore ~/.sonar/ssl/truststore.p12 -storepass $store_pass -noprompt -trustcacerts -importcert -alias sonar -file $RUNNER_TEMP/tmpcert.pem + scanner_args+=("-Dsonar.scanner.truststorePassword=$store_pass") +fi + +scanner_args+=("$@") + +set -ux + +$SCANNER_BIN "${scanner_args[@]}" + diff --git a/sanity-checks.sh b/sanity-checks.sh new file mode 100755 index 0000000..6fd8b97 --- /dev/null +++ b/sanity-checks.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -eo pipefail + +if [[ -z "${SONAR_TOKEN}" ]]; then + echo "::warning title=SonarScanner::Running this GitHub Action without SONAR_TOKEN is not recommended" +fi + +if [[ -f "${INPUT_PROJECTBASEDIR%/}/pom.xml" ]]; then + echo "::warning title=SonarScanner::Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action + to get more accurate results." +fi + +if [[ -f "${INPUT_PROJECTBASEDIR%/}/build.gradle" || -f "${INPUT_PROJECTBASEDIR%/}/build.gradle.kts" ]]; then + echo "::warning title=SonarScanner::Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action + to get more accurate results." +fi +