diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index a7ce91e..a700f69 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -28,7 +28,7 @@ jobs: - name: Verify the Docker image # profile for language 'web' is the last; assume everything is working if we got this far - run: docker logs -f ci |& sed '/Current profile for language web is Sonar way/ q' + run: docker logs -f ci |& sed "/Current profile for language 'web' is 'Sonar way'/ q" timeout-minutes: 3 - name: Stop the Docker image diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..247e495 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1b7f912 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# ICTU SonarQube contributing guidelines + +## What do I need to know to help? + +If you are looking to help to with a code contribution our project uses, you can find inspiration in the [issue list](https://github.com/ICTU/sonar/issues/). +Additionally, review the [MAINTENANCE](./MAINTENANCE.md) and [README](./README.md) documents. + +## How do I make a contribution? + +Never made an open source contribution before? Wondering how contributions work in the in our project? Here's a quick rundown! + +1. Find an issue that you are interested in addressing or a feature that you would like to add. +2. Fork the repository associated with the issue to your local GitHub organization. This means that you will have a copy of the repository under **your-GitHub-username/repository-name**. +3. Clone the repository to your local machine using `git clone https://github.com/github-username/repository-name.git`. +4. Create a new branch for your fix using `git checkout -b branch-name-here`. +5. Make the appropriate changes for the issue you are trying to address or the feature that you want to add. +6. Use git `add insert-paths-of-changed-files-here` to add the file contents of the changed files to the "snapshot" git uses to manage the state of the project, also known as the index. +7. Use `git commit -m "Insert a short message of the changes made here"` to store the contents of the index with a descriptive message. +8. Push the changes to the remote repository using `git push origin branch-name-here`. +9. Submit a pull request to the upstream repository. +10. Title the pull request with a short description of the changes made and the issue or bug number associated with your change. For example, you can title an issue like so "Added more log outputting to resolve #4352". +11. In the description of the pull request, explain the changes that you made, any issues you think exist with the pull request you made, and any questions you have for the maintainer. It's OK if your pull request is not perfect (no pull request is), the reviewer will be able to help you fix any problems and improve it! +12. Wait for the pull request to be reviewed by a maintainer. +13. Make changes to the pull request if the reviewing maintainer recommends them. +14. Celebrate your success after your pull request is merged! + +## Where can I go for help? + +If you need help, you can ask questions by [opening a new issue in this repository](https://github.com/ICTU/sonar/issues/new). + +## What does the Code of Conduct mean for me? + +Our [Code of Conduct](./CODE_OF_CONDUCT.md) means that you are responsible for treating everyone on the project with respect and courtesy regardless of their identity. +If you are the victim of any inappropriate behavior or comments as described in our Code of Conduct, we are here for you and will do the best to ensure that the abuser is reprimanded appropriately, per our code. diff --git a/Dockerfile b/Dockerfile index df2b8d8..367d9c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,38 @@ ARG IMAGE_NAME=sonarqube ARG IMAGE_VERSION=10.1.0 ARG IMAGE_EDITION=community + FROM $IMAGE_NAME:$IMAGE_VERSION-$IMAGE_EDITION + +LABEL org.opencontainers.image.authors="open-source-projects@ictu.nl" +LABEL org.opencontainers.image.url="https://github.com/ICTU/sonar" +LABEL org.opencontainers.image.documentation="https://raw.githubusercontent.com/ICTU/sonar/master/README.md" +LABEL org.opencontainers.image.source="https://raw.githubusercontent.com/ICTU/sonar/master/Dockerfile" +LABEL org.opencontainers.image.vendor="ICTU" +LABEL org.opencontainers.image.title="ICTU SonarQube" +LABEL org.opencontainers.image.description="A SonarQube image containing plugins, profiles and config used at ICTU" + USER root -RUN apt-get update && apt-get install -y wget curl ca-certificates-java jq postgresql-client \ + +RUN apt-get update \ + && apt-get install -y wget curl ca-certificates-java jq postgresql-client \ && rm -rf /var/lib/apt/lists/* + ADD ./plugins /tmp/plugins RUN rm -rf ./extensions/plugins/* && \ cat /tmp/plugins/plugin-list && \ chmod +x /tmp/plugins/install-plugins.sh && \ - ls /tmp/plugins -l && \ /tmp/plugins/install-plugins.sh + WORKDIR /opt/sonarqube + COPY ./start-with-profile.sh . ADD ./rules /tmp/rules ADD sonar.properties /opt/sonarqube/conf/sonar.properties -RUN chown -R sonarqube:sonarqube . && chmod +x start-with-profile.sh + +RUN chown -R sonarqube:sonarqube . \ + && chmod +x start-with-profile.sh + USER sonarqube + CMD ["./start-with-profile.sh"] diff --git a/README.md b/README.md index 665dd8e..ff44373 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# ICTU SonarQube Docker image +# ICTU SonarQube container image -A sonar image containing plugins and quality profiles used at ICTU +A sonar image containing plugins and quality profiles used at ICTU. ## Creating a new quality profile @@ -66,3 +66,8 @@ Alternatively, the `SONARQUBE_TOKEN` can be used as admin credential instead of The Sonar start script waits for the database to become available (only when using PostgreSQL). `DB_START_TIMEOUT` (default: 60 seconds) defines how long the script will wait for the database to become available before exiting. Similarly `SONAR_START_TIMEOUT` (default: 600 seconds) defines how long the script should wait for Sonar to start up. + + +## Get in touch + +Point of contact for this repository is [Dennie Bouman](https://github.com/ICTU/sonar/blob/master/@denniebouman). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a7fae83 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# ICTU SonarQube Security Policy + +## Current status + +The ICTU SonarQube container image has not implemented any hardening, but relies on the upstream [SonarQube container image](https://github.com/SonarSource/docker-sonarqube/). +In order to stay up to date, monitor SonarQube security findings and update accordingly. + +## Supported Versions + +Only the latest version of the ICTU SonarQube container image is currently being supported with security updates. +The intention is to keep the container image based on a recent SonarQube version, there is no incentive to patch older tags. + +## Reporting a Vulnerability + +Please report security vulnerabilities by [opening an issue on github](https://github.com/ICTU/sonar/issues/new), or by email to . +The aim is to get back to you within 24 hours with a confirmation of the issue and a brief action plan or a request for more information. diff --git a/docker/docker-compose.ci.yml b/docker/docker-compose.ci.yml new file mode 100644 index 0000000..f0f5e2d --- /dev/null +++ b/docker/docker-compose.ci.yml @@ -0,0 +1,17 @@ +--- +version: "3.7" + +services: + www: + build: + args: + IMAGE_EDITION: "developer" + environment: + SONAR_JDBC_USERNAME: "sonar_user" + SONAR_JDBC_PASSWORD: "sonar_pass" + SONARQUBE_PASSWORD: "admin123" + + db: + environment: + POSTGRES_USER: "sonar_user" + POSTGRES_PASSWORD: "sonar_pass" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..d718ff3 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,32 @@ +--- +version: "3.7" + +services: + www: + build: + context: .. + environment: + SONAR_JDBC_URL: "jdbc:postgresql://db:5432/sonar" + ports: + - mode: ingress + target: 9000 + published: 9001 + volumes: + - type: "volume" + source: "plugins" + target: "/opt/sonarqube/extensions/plugins" + depends_on: + - db + + db: + image: postgres:16.0-alpine3.18 + environment: + POSTGRES_DB: "sonar" + POSTGRES_HOST_AUTH_METHOD: "scram-sha-256" + POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256" + volumes: + - "dbdata:/var/lib/postgresql/data:rw" + +volumes: + dbdata: + plugins: diff --git a/plugins/plugin-list b/plugins/plugin-list index 557d6a6..d45b3f5 100644 --- a/plugins/plugin-list +++ b/plugins/plugin-list @@ -1,7 +1,7 @@ https://github.com/checkstyle/sonar-checkstyle/releases/download/10.12.3/checkstyle-sonar-plugin-10.12.3.jar https://github.com/dependency-check/dependency-check-sonar-plugin/releases/download/4.0.0/sonar-dependency-check-plugin-4.0.0.jar https://github.com/jborgers/sonar-pmd/releases/download/3.4.0/sonar-pmd-plugin-3.4.0.jar +https://github.com/sbaudoin/sonar-ansible/releases/download/v2.5.1/sonar-ansible-plugin-2.5.1.jar https://github.com/sbaudoin/sonar-yaml/releases/download/v1.7.0/sonar-yaml-plugin-1.7.0.jar -https://github.com/spotbugs/sonar-findbugs/releases/download/4.2.3/sonar-findbugs-plugin-4.2.3.jar +https://github.com/spotbugs/sonar-findbugs/releases/download/4.2.4/sonar-findbugs-plugin-4.2.4.jar https://github.com/vaulttec/sonar-auth-oidc/releases/download/v2.1.1/sonar-auth-oidc-plugin-2.1.1.jar -https://github.com/sbaudoin/sonar-ansible/releases/download/v2.5.1/sonar-ansible-plugin-2.5.1.jar diff --git a/rules/swift.txt b/rules/swift.txt new file mode 100644 index 0000000..dc2e457 --- /dev/null +++ b/rules/swift.txt @@ -0,0 +1,7 @@ ++types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default ++swift:S1541|Threshold=10 # Used by Quality-time (https://github.com/ICTU/quality-time/blob/master/docs/METRICS_AND_SOURCES.md#complex-units-from-sonarqube) ++swift:S1067 # Expression too complex; NOT used by Quality-time ++swift:S138|max=20 # Methods with too many lines; used by Quality-time (https://github.com/ICTU/quality-time/blob/master/docs/METRICS_AND_SOURCES.md#long-units-from-sonarqube) ++swift:S107|functionMax=5 # Too many parameters; used by Quality-time (https://github.com/ICTU/quality-time/blob/master/docs/METRICS_AND_SOURCES.md#many-parameters-from-sonarqube) ++swift:S125 # Used by Quality-time (https://github.com/ICTU/quality-time/blob/master/docs/METRICS_AND_SOURCES.md#commented-out-code-from-sonarqube) +#end please ensure every rule ends with a new line character diff --git a/start-with-profile.sh b/start-with-profile.sh index 5376262..f2eb902 100644 --- a/start-with-profile.sh +++ b/start-with-profile.sh @@ -1,35 +1,34 @@ #!/bin/bash -if [[ -n $SONARQUBE_TOKEN ]]; then - BASIC_AUTH="$SONARQUBE_TOKEN:" +if [[ -n "${SONARQUBE_TOKEN}" ]]; then + BASIC_AUTH="${SONARQUBE_TOKEN}:" else BASIC_AUTH="${SONARQUBE_USERNAME:-admin}:${SONARQUBE_PASSWORD:-admin}" fi # Access SonarQube api with admin credentials function curlAdmin { - curl -v -u "$BASIC_AUTH" "$@" + curl -s -u "${BASIC_AUTH}" "$@" | awk 1 } # Check if the database is ready for connections function waitForDatabase { # get HOST:PORT from JDBC URL - if [[ $SONAR_JDBC_URL =~ postgresql://([^:/]+)(:([0-9]+))?/ ]]; then + if [[ "${SONAR_JDBC_URL}" =~ postgresql://([^:/]+)(:([0-9]+))?/ ]]; then local host=${BASH_REMATCH[1]} local port=${BASH_REMATCH[3]:-5432} else echo "Only PostgreSQL databases are supported" return fi - echo "Waiting for database connection on $host:$port" + echo "Waiting for database connection on ${host}:${port}" local count=0 local sleep=5 local timeout=${DB_START_TIMEOUT:-60} - until pg_isready -h "$host" -p "$port" ${SONAR_JDBC_USERNAME:+-U "$SONAR_JDBC_USERNAME"} + until pg_isready -h "${host}" -p "${port}" ${SONAR_JDBC_USERNAME:+-U "$SONAR_JDBC_USERNAME"} do - if [[ count -gt timeout ]] - then - echo "ERROR: Failed to start database within $timeout seconds" + if [[ count -gt timeout ]]; then + echo "ERROR: Failed to start database within ${timeout} seconds" exit 1 fi echo "Waiting for database connection..." @@ -37,7 +36,7 @@ function waitForDatabase { sleep $sleep count=$((count+sleep)) done - echo "Database listening on ${HOSTPORT}" + echo "Database listening on ${host}:${port}" } # Wait until SonarQube is operational @@ -46,15 +45,14 @@ function waitForSonarUp { local sleep=5 local timeout=${SONAR_START_TIMEOUT:-600} # Wait for server to be up - until [[ "$status" == "UP" ]] + until [[ "${status}" == "UP" ]] do - if [[ count -gt timeout ]] - then - echo "ERROR: Failed to start Sonar within $timeout seconds" + if [[ count -gt timeout ]]; then + echo "ERROR: Failed to start Sonar within ${timeout} seconds" exit 1 fi - status=$(curl -s -f "$BASE_URL/api/system/status" | jq -r '.status') - echo "Waiting for sonar to come up: $status" + status=$(curl -s -f "${BASE_URL}/api/system/status" | jq -r '.status') + echo "Waiting for sonar to come up: ${status}" sleep $sleep count=$((count+sleep)) done @@ -63,16 +61,16 @@ function waitForSonarUp { # Try to change the default admin password to the one provided in SONARQUBE_PASSWORD function changeDefaultAdminPassword { - if [ -n "$SONARQUBE_PASSWORD" ]; then + if [ -n "${SONARQUBE_PASSWORD}" ]; then echo "Trying to change the default admin password" - curl -s -X POST -u "admin:admin" -f "$BASE_URL/api/users/change_password?login=admin&password=${SONARQUBE_PASSWORD}&previousPassword=admin" + curl -s -X POST -u "admin:admin" -f "${BASE_URL}/api/users/change_password?login=admin&password=${SONARQUBE_PASSWORD}&previousPassword=admin" fi } # Test admin credentials function testAdminCredentials { - authenticated=$(curl -s -u "$BASIC_AUTH" -f "$BASE_URL/api/system/info") - if [ -z "$authenticated" ]; then + authenticated=$(curl -s -u "${BASIC_AUTH}" -f "${BASE_URL}/api/system/info") + if [ -z "${authenticated}" ]; then echo "################################################################################" echo "No or incorrect admin credentials provided. Shutting down SonarQube..." echo "################################################################################" @@ -84,10 +82,12 @@ function testAdminCredentials { function getProfileKey { local searchProfileName=$1 local searchLanguage=$2 - local getProfileKeyUrl="$BASE_URL/api/qualityprofiles/search?qualityProfile=$searchProfileName&language=$searchLanguage" - local json=$(curl -u "$BASIC_AUTH" "$getProfileKeyUrl") - local searchResultProfileKey=$(echo "$json" | grep -Eo '"key":"([_A-Z0-9a-z-]*)"' | cut -d: -f2 | sed -r 's/"//g') - echo "$searchResultProfileKey" + local getProfileKeyUrl json searchResultProfileKey + + getProfileKeyUrl="${BASE_URL}/api/qualityprofiles/search?qualityProfile=${searchProfileName}&language=${searchLanguage}" + json=$(curl -s -u "${BASIC_AUTH}" "${getProfileKeyUrl}") + searchResultProfileKey=$(echo "${json}" | grep -Eo '"key":"([_A-Z0-9a-z-]*)"' | cut -d: -f2 | sed -r 's/"//g') + echo "${searchResultProfileKey}" } function processRule { @@ -95,56 +95,50 @@ function processRule { local profileKey=$2 local language=$3 - echo "Optimize rule" - rule=$(echo $rule |tr -d ' ' | cut -d "#" -f 1) + rule=$(echo "${rule}" |tr -d ' ' | cut -d "#" -f 1) + echo "Processing rule '${rule}'" # The first character is the operation # + = activate # - = deactivate - local operationType=${rule:0:1} + local operationType="${rule:0:1}" # After the operation comes the SonarQube ruleSet which contains ruleId and ruleParams - local ruleSet=${rule:1} + local ruleSet="${rule:1}" # Enable rules by group (types) - if [[ $ruleSet =~ types=.* ]]; then + if [[ "${ruleSet}" =~ types=.* ]]; then - IFS='=' read -r typekey ruleTypes <<< "$ruleSet" - if [ "$operationType" == "+" ]; then + IFS='=' read -r typekey ruleTypes <<< "${ruleSet}" + if [ "${operationType}" == "+" ]; then echo "Activating rules ${ruleTypes} for ${language}" - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/activate_rules?targetKey=${profileKey}&languages=${language}&types=${ruleTypes}&statuses=READY" - fi - if [ "$operationType" == "-" ]; then + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/activate_rules?targetKey=${profileKey}&languages=${language}&types=${ruleTypes}&statuses=READY" + elif [ "${operationType}" == "-" ]; then echo "Deactivating rules ${ruleTypes} for ${language}" - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/deactivate_rules?targetKey=${profileKey}&languages=${language}&types=${ruleTypes}" + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/deactivate_rules?targetKey=${profileKey}&languages=${language}&types=${ruleTypes}" fi else - IFS='|' read -r ruleId ruleParams <<< "$ruleSet" - ruleParams=${ruleParams/|/,} + IFS='|' read -r ruleId ruleParams <<< "${ruleSet}" + ruleParams="${ruleParams/|/,}" - echo "*** Processing rule ***" - echo "Rule ${rule}" - echo "Operation ${operationType}" - echo "RuleId ${ruleId}" - echo "RuleParams ${ruleParams}" + echo "Rule: '${rule}', Operation: '${operationType}'" + echo "RuleId: '${ruleId}', RuleParams: '${ruleParams}'" - if [ "$operationType" == "+" ]; then + if [ "${operationType}" == "+" ]; then echo "Activating rule ${ruleId}" - if [ "$ruleParams" == "" ]; then - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/activate_rule?key=$profileKey&rule=$ruleId" + if [ "${ruleParams}" == "" ]; then + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/activate_rule?key=${profileKey}&rule=${ruleId}" else - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/activate_rule?key=$profileKey&rule=$ruleId¶ms=$ruleParams" + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/activate_rule?key=${profileKey}&rule=${ruleId}¶ms=${ruleParams}" fi - fi - - if [ "$operationType" == "-" ]; then + elif [ "${operationType}" == "-" ]; then echo "Deactivating rule ${ruleId}" - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/deactivate_rule?key=$profileKey&rule=$ruleId" + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/deactivate_rule?key=${profileKey}&rule=${ruleId}" fi - fi # [[ $ruleSet =~ types.* ]]; + fi } # Create a new SonarQube profile with custom activated rules, inheritance and set as default @@ -162,18 +156,18 @@ function createProfile { # create profile # curlAdmin -X POST "$BASE_URL/api/qualityprofiles/create?name=$profileName&language=$language" # curlAdmin -X POST --data "qualityProfile=$1&parentQualityProfile=$2&language=$3" "$BASE_URL/api/qualityprofiles/change_parent" - echo "Copying the profile $baseProfileName $language to $profileName" - baseProfileKey=$(getProfileKey "$baseProfileName" "$language") - copyProfileUrl="$BASE_URL/api/qualityprofiles/copy?toName=$profileName&fromKey=$baseProfileKey" - echo "Posting to $copyProfileUrl" - curlAdmin -X POST "$copyProfileUrl" + echo "Copying the profile ${baseProfileName} ${language} to ${profileName}" + baseProfileKey=$(getProfileKey "${baseProfileName}" "${language}") + copyProfileUrl="${BASE_URL}/api/qualityprofiles/copy?toName=${profileName}&fromKey=${baseProfileKey}" + echo "Posting to ${copyProfileUrl}" + curlAdmin -X POST "${copyProfileUrl}" - profileKey=$(getProfileKey "$profileName" "$language") - echo "The profile $profileName $language has the key $profileKey" + profileKey=$(getProfileKey "${profileName}" "${language}") + echo "The profile '${profileName}' of '${language}' has the key '${profileKey}'" - if [[ -f "$rulesFilename" ]]; then + if [[ -f "${rulesFilename}" ]]; then # activate and deactivate rules in new profile - while read ruleLine || [ -n "$line" ]; do + while read ruleLine || [ -n "${line}" ]; do # Each line contains: # (+|-)types=comma-seperated,list-of-types # comment @@ -182,56 +176,55 @@ function createProfile { # +cs:1032 # some comment # +types=SECURITY_HOTSPOT,VULNERABILITY # some comment IFS='#';ruleSplit=("${ruleLine}");unset IFS; - rule=${ruleSplit[0]} - comment=${ruleSplit[1]} + rule="${ruleSplit[0]}" - processRule "$rule" "$profileKey" "$language" + processRule "${rule}" "${profileKey}" "${language}" - done < "$rulesFilename" + done < "${rulesFilename}" fi # if the PROJECT_RULES environment variable is defined and not empty, create a custom project profile - echo "Project specific rules = $PROJECT_RULES" - if [[ -n "$PROJECT_RULES" ]]; then + echo "Project specific rules = ${PROJECT_RULES}" + if [[ -n "${PROJECT_RULES}" ]]; then echo "Creating custom project profile" - local projectProfileName=$PROJECT_CODE-$profileName - echo "Project custom profile name is $projectProfileName" + local projectProfileName="${PROJECT_CODE}-${profileName}" + echo "Project custom profile name is '${projectProfileName}'" # create project specific profile # curlAdmin -X POST "$BASE_URL/api/qualityprofiles/create?name=$projectProfileName&language=$language" # curlAdmin -X POST --data "qualityProfile=$projectProfileName&parentQualityProfile=$profileName&language=$3" "$BASE_URL/api/qualityprofiles/change_parent" - echo "Copying the profile $baseProfileName $language to $profileName" - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/copy?fromKey=$profileKey&toName=$projectProfileName" + echo "Copying the profile '${baseProfileName}' of '${language}' to '${profileName}'" + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/copy?fromKey=${profileKey}&toName=${projectProfileName}" # retrieve the new profile key - profileKey=$(getProfileKey "$projectProfileName" "$language") - echo "The profile $projectProfileName $language has the key $profileKey" + profileKey=$(getProfileKey "${projectProfileName}" "${language}") + echo "The profile '${projectProfileName}' of '${language}' has the key '${profileKey}'" - IFS=';' read -ra projrules <<< "$PROJECT_RULES" + IFS=';' read -ra projrules <<< "${PROJECT_RULES}" for rule in "${projrules[@]}"; do - echo "Processing project custom rule $rule" - processRule "$rule" "$profileKey" "$language" + echo "Processing project custom rule ${rule}" + processRule "${rule}" "${profileKey}" "${language}" done # mark this profile to be activated - profileName=$projectProfileName + profileName="${projectProfileName}" fi # get current default profile name - currentProfileName=$(curl -u "$BASIC_AUTH" -s "$BASE_URL/api/qualityprofiles/search?defaults=true" | jq -r --arg LANGUAGE "$3" '.profiles[] | select(.language==$LANGUAGE) | .name') - echo "Current profile for language $3 is $currentProfileName" + currentProfileName=$(curl -s -u "${BASIC_AUTH}" "${BASE_URL}/api/qualityprofiles/search?defaults=true" | jq -r --arg LANGUAGE "$3" '.profiles[] | select(.language==$LANGUAGE) | .name') + echo "Current profile for language '$3' is '${currentProfileName}'" # set profile as default only when name does not end in DEFAULT or default shopt -s nocasematch - if [[ $currentProfileName =~ .*DEFAULT$ ]]; then - echo "Keeping current default profile $currentProfileName for language $3" + if [[ "${currentProfileName}" =~ .*DEFAULT$ ]]; then + echo "Keeping current default profile '${currentProfileName}' for language '$3'" else - if [[ $currentProfileName =~ .*EXTENDED$ ]]; then - echo "Changing parent of extended profile $currentProfileName for language $3 to $profileName" - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/change_parent?qualityProfile=$currentProfileName&parentQualityProfile=$profileName&language=$3" + if [[ "${currentProfileName}" =~ .*EXTENDED$ ]]; then + echo "Changing parent of extended profile '${currentProfileName}' for language '$3' to '${profileName}'" + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/change_parent?qualityProfile=${currentProfileName}&parentQualityProfile=${profileName}&language=$3" else - echo "Setting profile $profileName for language $3 as default" - curlAdmin -X POST "$BASE_URL/api/qualityprofiles/set_default?qualityProfile=$profileName&language=$3" + echo "Setting profile '${profileName}' for language '$3' as default" + curlAdmin -X POST "${BASE_URL}/api/qualityprofiles/set_default?qualityProfile=${profileName}&language=$3" fi fi } @@ -239,10 +232,10 @@ function createProfile { ########################################################################################################################### # Main ########################################################################################################################### -BASE_URL=http://127.0.0.1:9000 +BASE_URL="http://127.0.0.1:9000" # waitForDatabase -if [ "$SONAR_JDBC_URL" ]; then +if [ "${SONAR_JDBC_URL}" ]; then waitForDatabase fi @@ -250,8 +243,8 @@ fi function shutdown { echo "Shutdown" if [[ -n $PID ]]; then - kill $PID - wait $PID + kill "${PID}" + wait "${PID}" fi } trap "shutdown" EXIT @@ -268,14 +261,22 @@ testAdminCredentials # (Re-)create the ICTU profiles RULES_VERSION=20230619 +echo "*** Start processing rules for version ${RULES_VERSION} ***" createProfile "ictu-ansible-profile-v2.5.1-${RULES_VERSION}" "Sonar%20way" "yaml" # custom sonar-ansible-plugin createProfile "ictu-cs-profile-v9.3.0-${RULES_VERSION}" "Sonar%20way" "cs" # image csharp-plugin createProfile "ictu-java-profile-v7.20.0-${RULES_VERSION}" "Sonar%20way" "java" # image java-plugin createProfile "ictu-js-profile-v10.3.1-${RULES_VERSION}" "Sonar%20way" "js" # image javascript-plugin createProfile "ictu-kotlin-profile-v2.15.0-${RULES_VERSION}" "Sonar%20way" "kotlin" # image kotlin-plugin createProfile "ictu-py-profile-v4.3.0-${RULES_VERSION}" "Sonar%20way" "py" # image python-plugin +createProfile "ictu-swift-profile-v4.9.0-${RULES_VERSION}" "Sonar%20way" "swift" # image swift-plugin createProfile "ictu-ts-profile-v10.3.1-${RULES_VERSION}" "Sonar%20way" "ts" # image javascript-plugin createProfile "ictu-vbnet-profile-v9.3.0-${RULES_VERSION}" "Sonar%20way" "vbnet" # image vbnet-plugin createProfile "ictu-web-profile-v3.8.0-${RULES_VERSION}" "Sonar%20way" "web" # image html-plugin +echo "*** Finished processing rules ***" + +echo "" +echo "" +echo "SonarQube started with ICTU profiles" +echo "" wait $PID