From b8a8448d4a72175c6d589284e5294f773c64984d Mon Sep 17 00:00:00 2001 From: wkoot <3715211+wkoot@users.noreply.github.com> Date: Tue, 13 Feb 2024 12:08:40 +0100 Subject: [PATCH 1/6] Update to v4 checkout action and address warnings --- .github/workflows/docker-image.yml | 2 +- Dockerfile | 6 +++--- plugins/install-plugins.sh | 17 ++++++++++------- start-with-profile.sh | 4 ++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index a700f69..d130897 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -18,7 +18,7 @@ jobs: - env: IMAGE_EDITION: developer steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build the Docker image run: docker build --build-arg="IMAGE_EDITION=${{ matrix.env.IMAGE_EDITION }}" -t ci . diff --git a/Dockerfile b/Dockerfile index 02e4f4b..cbea376 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ 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 +COPY ./plugins /tmp/plugins RUN rm -rf ./extensions/plugins/* && \ cat /tmp/plugins/plugin-list && \ chmod +x /tmp/plugins/install-plugins.sh && \ @@ -27,8 +27,8 @@ RUN rm -rf ./extensions/plugins/* && \ WORKDIR /opt/sonarqube COPY ./start-with-profile.sh . -ADD ./rules /tmp/rules -ADD sonar.properties /opt/sonarqube/conf/sonar.properties +COPY ./rules /tmp/rules +COPY sonar.properties /opt/sonarqube/conf/sonar.properties RUN chown -R sonarqube:sonarqube . \ && chmod +x start-with-profile.sh diff --git a/plugins/install-plugins.sh b/plugins/install-plugins.sh index 99b831e..67abcfa 100755 --- a/plugins/install-plugins.sh +++ b/plugins/install-plugins.sh @@ -1,19 +1,22 @@ #!/bin/bash cwd="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -plugin_dir=/opt/sonarqube/extensions/plugins +plugin_dir="/opt/sonarqube/extensions/plugins" # Download plugins -while read plugin; do - wget $plugin -P $plugin_dir +while read -r plugin; do + wget --no-verbose "${plugin}" -P "${plugin_dir}" rtn=$? if [ $rtn -ne 0 ]; then - echo "Error downloading $plugin" + echo "Error downloading ${plugin}" exit $rtn fi -done < $cwd/plugin-list +done < "${cwd}"/plugin-list # Check if unzip required -for file in $plugin_dir/*; do - if [[ $file =~ \.zip$ ]]; then unzip $file -d $plugin_dir && rm -f $file; fi +for file in "${plugin_dir}"/*; do + if [[ $file =~ \.zip$ ]]; then + unzip "${file}" -d "${plugin_dir}" + rm -f "${file}" + fi done diff --git a/start-with-profile.sh b/start-with-profile.sh index 1409805..042240b 100644 --- a/start-with-profile.sh +++ b/start-with-profile.sh @@ -109,7 +109,7 @@ function processRule { # Enable rules by group (types) if [[ "${ruleSet}" =~ types=.* ]]; then - IFS='=' read -r typekey ruleTypes <<< "${ruleSet}" + IFS='=' read -r _ 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" @@ -167,7 +167,7 @@ function createProfile { if [[ -f "${rulesFilename}" ]]; then # activate and deactivate rules in new profile - while read ruleLine || [ -n "${line}" ]; do + while read -r ruleLine || [ -n "${line}" ]; do # Each line contains: # (+|-)types=comma-seperated,list-of-types # comment From ac5bd85fba7f65c903b886bd3aaa9903782efdd3 Mon Sep 17 00:00:00 2001 From: wkoot <3715211+wkoot@users.noreply.github.com> Date: Tue, 13 Feb 2024 14:15:50 +0100 Subject: [PATCH 2/6] Set up python tests --- .github/workflows/docker-image.yml | 22 +++++++++++++++------- tests/__init__.py | 0 tests/requirements.txt | 2 ++ tests/test_smoke.py | 17 +++++++++++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/requirements.txt create mode 100644 tests/test_smoke.py diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index d130897..2374b46 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -20,16 +20,24 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Build the Docker image - run: docker build --build-arg="IMAGE_EDITION=${{ matrix.env.IMAGE_EDITION }}" -t ci . + - name: Build and run container image + run: | + docker build --build-arg="IMAGE_EDITION=${{ matrix.env.IMAGE_EDITION }}" -t ci . + docker run -v $(pwd)/tests:/opt/sonarqube/test -d --name ci ci - - name: Run the Docker image - run: docker run -d --name ci ci - - - name: Verify the Docker image + - name: Wait for Sonar instance to start # 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" timeout-minutes: 3 - - name: Stop the Docker image + - name: Install test requirements + run: | + docker exec -u 0:0 ci apt-get update + docker exec -u 0:0 ci apt-get install -y python3 python3-pip + docker exec -u 0:0 ci pip3 install -Ur /opt/sonarqube/test/requirements.txt + + - name: Run tests + run: docker exec ci python3 -m unittest -v + + - name: Stop the container run: docker stop ci diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..45713d5 --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,2 @@ +python-sonarqube-api >= 2.0 +requests >= 2.31 diff --git a/tests/test_smoke.py b/tests/test_smoke.py new file mode 100644 index 0000000..c70c5d4 --- /dev/null +++ b/tests/test_smoke.py @@ -0,0 +1,17 @@ +from os import getenv +from unittest import TestCase + +from sonarqube import SonarQubeClient + + +class SonarTest(TestCase): + def setUp(self) -> None: + sonar_port = getenv("SONAR_PORT", "9000") + sonar_base_url = f"http://localhost:{sonar_port}" + sonar_pass = getenv("SONARQUBE_PASSWORD", "admin") + self.sonar_client = SonarQubeClient(sonarqube_url=sonar_base_url, username="admin", password=sonar_pass) + + def test_java_profile(self): + java_quality_profiles = self.sonar_client.qualityprofiles.search_quality_profiles(language="java") + java_profile_names = [profile["name"] for profile in java_quality_profiles["profiles"]] + self.assertIn("Sonar way", java_profile_names) From 000e81dcba068b0f62fce432fe0dd79e1b5deb96 Mon Sep 17 00:00:00 2001 From: wkoot <3715211+wkoot@users.noreply.github.com> Date: Thu, 15 Feb 2024 21:18:28 +0100 Subject: [PATCH 3/6] test env var in test --- .github/workflows/docker-image.yml | 8 ++++++-- docker/docker-compose.ci.yml | 2 ++ tests/test_smoke.py | 23 ++++++++++++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 2374b46..6f83912 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -7,6 +7,10 @@ on: pull_request: types: [opened, synchronize, reopened] +env: + CODE: "PROJ1" + RULES: "+csharpsquid:S104;-ts:S1561" + jobs: build: runs-on: ubuntu-latest @@ -23,7 +27,7 @@ jobs: - name: Build and run container image run: | docker build --build-arg="IMAGE_EDITION=${{ matrix.env.IMAGE_EDITION }}" -t ci . - docker run -v $(pwd)/tests:/opt/sonarqube/test -d --name ci ci + docker run -e PROJECT_CODE="${{ env.CODE }}" -e PROJECT_RULES="${{ env.RULES }}" -v $(pwd)/tests:/opt/sonarqube/test -d --name ci ci - name: Wait for Sonar instance to start # profile for language 'web' is the last; assume everything is working if we got this far @@ -37,7 +41,7 @@ jobs: docker exec -u 0:0 ci pip3 install -Ur /opt/sonarqube/test/requirements.txt - name: Run tests - run: docker exec ci python3 -m unittest -v + run: docker exec -e PROJECT_CODE="${{ env.CODE }}" -e PROJECT_RULES="${{ env.RULES }}" ci python3 -m unittest -v - name: Stop the container run: docker stop ci diff --git a/docker/docker-compose.ci.yml b/docker/docker-compose.ci.yml index f0f5e2d..9f40cc1 100644 --- a/docker/docker-compose.ci.yml +++ b/docker/docker-compose.ci.yml @@ -10,6 +10,8 @@ services: SONAR_JDBC_USERNAME: "sonar_user" SONAR_JDBC_PASSWORD: "sonar_pass" SONARQUBE_PASSWORD: "admin123" + PROJECT_CODE: "PROJ1" + PROJECT_RULES: "+csharpsquid:S104;-ts:S1561" db: environment: diff --git a/tests/test_smoke.py b/tests/test_smoke.py index c70c5d4..f80a9db 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -1,8 +1,11 @@ from os import getenv -from unittest import TestCase +from unittest import TestCase, skipUnless from sonarqube import SonarQubeClient +PROJECT_CODE = getenv("PROJECT_CODE") +PROJECT_RULES = getenv("PROJECT_RULES") + class SonarTest(TestCase): def setUp(self) -> None: @@ -15,3 +18,21 @@ def test_java_profile(self): java_quality_profiles = self.sonar_client.qualityprofiles.search_quality_profiles(language="java") java_profile_names = [profile["name"] for profile in java_quality_profiles["profiles"]] self.assertIn("Sonar way", java_profile_names) + + @skipUnless(PROJECT_CODE, "PROJECT_CODE was not passed") + def test_csharpsquid_profile(self): + search_result = self.sonar_client.qualityprofiles.search_quality_profiles( + defaults="true", language="cs", qualityProfile=f"{PROJECT_CODE}-ictu-cs-profile-v9.13.0-20231222" + ) + self.assertEqual(len(search_result['profiles']), 1) + cs_profile_key = search_result['profiles'][0]['key'] + self.assertIsNotNone(cs_profile_key) # TODO - check activated rules within profile instead + + @skipUnless(PROJECT_CODE, "PROJECT_CODE was not passed") + def test_ts_profile(self): + search_result = self.sonar_client.qualityprofiles.search_quality_profiles( + defaults="true", language="ts", qualityProfile=f"{PROJECT_CODE}-ictu-ts-profile-v10.9.0-20231222" + ) + self.assertEqual(len(search_result['profiles']), 1) + ts_profile_key = search_result['profiles'][0]['key'] + self.assertIsNotNone(ts_profile_key) # TODO - check activated rules within profile instead From 2150ea6e133ffc3da8e968f41f64dea5f78cf6a7 Mon Sep 17 00:00:00 2001 From: wkoot <3715211+wkoot@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:19:11 +0100 Subject: [PATCH 4/6] Move config to json file and refactor scripts --- Dockerfile | 20 +- plugins/plugin-list | 6 - rules/.gitattributes | 1 - rules/cs.txt | 12 - rules/java.txt | 17 -- rules/js.txt | 12 - rules/kotlin.txt | 7 - rules/py.txt | 9 - rules/swift.txt | 11 - rules/ts.txt | 11 - rules/vbnet.txt | 9 - rules/web.txt | 6 - rules/yaml.txt | 50 ----- src/config.json | 211 ++++++++++++++++++ {plugins => src}/install-plugins.sh | 4 +- .../start-with-profile.sh | 49 ++-- 16 files changed, 241 insertions(+), 194 deletions(-) delete mode 100644 plugins/plugin-list delete mode 100644 rules/.gitattributes delete mode 100644 rules/cs.txt delete mode 100644 rules/java.txt delete mode 100644 rules/js.txt delete mode 100644 rules/kotlin.txt delete mode 100644 rules/py.txt delete mode 100644 rules/swift.txt delete mode 100644 rules/ts.txt delete mode 100644 rules/vbnet.txt delete mode 100644 rules/web.txt delete mode 100644 rules/yaml.txt create mode 100644 src/config.json rename {plugins => src}/install-plugins.sh (83%) mode change 100755 => 100644 rename start-with-profile.sh => src/start-with-profile.sh (84%) diff --git a/Dockerfile b/Dockerfile index cbea376..08a1728 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,21 +18,15 @@ RUN apt-get update \ && apt-get install -y wget curl ca-certificates-java jq postgresql-client \ && rm -rf /var/lib/apt/lists/* -COPY ./plugins /tmp/plugins -RUN rm -rf ./extensions/plugins/* && \ - cat /tmp/plugins/plugin-list && \ - chmod +x /tmp/plugins/install-plugins.sh && \ - /tmp/plugins/install-plugins.sh - -WORKDIR /opt/sonarqube - -COPY ./start-with-profile.sh . -COPY ./rules /tmp/rules COPY sonar.properties /opt/sonarqube/conf/sonar.properties +COPY ./src /src +RUN chmod +x /src/ /src/*.sh && \ + rm -rf ./extensions/plugins/* && \ + /src/install-plugins.sh -RUN chown -R sonarqube:sonarqube . \ - && chmod +x start-with-profile.sh +WORKDIR /opt/sonarqube +RUN chown -R sonarqube:sonarqube . USER sonarqube -CMD ["./start-with-profile.sh"] +CMD ["/src/start-with-profile.sh"] diff --git a/plugins/plugin-list b/plugins/plugin-list deleted file mode 100644 index 8a03792..0000000 --- a/plugins/plugin-list +++ /dev/null @@ -1,6 +0,0 @@ -https://github.com/checkstyle/sonar-checkstyle/releases/download/10.12.5/checkstyle-sonar-plugin-10.12.5.jar -https://github.com/dependency-check/dependency-check-sonar-plugin/releases/download/4.0.1/sonar-dependency-check-plugin-4.0.1.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.9.1/sonar-yaml-plugin-1.9.1.jar -https://github.com/spotbugs/sonar-findbugs/releases/download/4.2.6/sonar-findbugs-plugin-4.2.6.jar -https://github.com/vaulttec/sonar-auth-oidc/releases/download/v2.1.1/sonar-auth-oidc-plugin-2.1.1.jar diff --git a/rules/.gitattributes b/rules/.gitattributes deleted file mode 100644 index 07764a7..0000000 --- a/rules/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text eol=lf \ No newline at end of file diff --git a/rules/cs.txt b/rules/cs.txt deleted file mode 100644 index 84d0b3b..0000000 --- a/rules/cs.txt +++ /dev/null @@ -1,12 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+csharpsquid:S104 # NCSS; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+csharpsquid:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters) -+csharpsquid:S125 # Commented code; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code) -+csharpsquid:S134 # Depth of nesting; NOT used by Quality-time -+csharpsquid:S1067 # Too complex expression; NOT used by Quality-time -+csharpsquid:S109 # Magic numbers; NOT used by Quality-time -+csharpsquid:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+csharpsquid:S1309 # Violation suppression; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations) -+csharpsquid:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units) -+csharpsquid:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time -#end please ensure every rule ends with a new line character diff --git a/rules/java.txt b/rules/java.txt deleted file mode 100644 index e9d8886..0000000 --- a/rules/java.txt +++ /dev/null @@ -1,17 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+java:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units) -+java:NoSonar # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations) -+java:S1309 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations) -+java:S1310 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations) -+java:S1315 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations) -+java:S1067 # Expression too complex; NOT used by Quality-time -+java:S109 # Magic numbers; NOT used by Quality-time -+java:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+java:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters) -+java:S125 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code) -+java:S104 # Files should not have too many lines of code. Used by Quality-time -+java:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time -+java:S1188 # Anonymous classes should not have too many lines. Used by Quality-time -+java:S2972 # Inner classes should not have too many lines of code. Used by Quality-time -+java:S5612 # Lambdas should not have too many lines. Used by Quality-time -#end please ensure every rule ends with a new line character diff --git a/rules/js.txt b/rules/js.txt deleted file mode 100644 index 1b5c71a..0000000 --- a/rules/js.txt +++ /dev/null @@ -1,12 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+javascript:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units) -+javascript:S134 # NOT used by Quality-time -+javascript:S1067 # Expression too complex; NOT used by Quality-time -+javascript:S106 # Console logging should not be used; NOT used by Quality-time -+javascript:S107|maximumFunctionParameters=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters) -+javascript:S109 # Magic numbers; NOT used by Quality-time -+javascript:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+javascript:S125 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code) -+javascript:S104 # Files should not have too many lines of code. Used by Quality-time -# Missing: NoSonar, NCSS, Parameters -#end please ensure every rule ends with a new line character diff --git a/rules/kotlin.txt b/rules/kotlin.txt deleted file mode 100644 index 6412307..0000000 --- a/rules/kotlin.txt +++ /dev/null @@ -1,7 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+kotlin:S1067 # Expression too complex; NOT used by Quality-time -+kotlin:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+kotlin:S107|Max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters) -+kotlin:S104 # Files should not have too many lines of code. Used by Quality-time -+kotlin:S1151 # When clauses should not have too many lines of code. Used by Quality-time -+kotlin:S5612 # Lambdas should not have too many lines. Used by Quality-time diff --git a/rules/py.txt b/rules/py.txt deleted file mode 100644 index 6021113..0000000 --- a/rules/py.txt +++ /dev/null @@ -1,9 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+python:S104 # Too many lines of code in file; NOT used by Quality-time -+python:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters) -+python:NoSonar # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations) -+python:S125 # Commented code; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code) -+python:S134 # Too deep nesting; NOT used by Quality-time -+python:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+python:FunctionComplexity|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units) -#end please ensure every rule ends with a new line character diff --git a/rules/swift.txt b/rules/swift.txt deleted file mode 100644 index ea301e6..0000000 --- a/rules/swift.txt +++ /dev/null @@ -1,11 +0,0 @@ -+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) -+swift:S104 # Files should not have too many lines of code. Used by Quality-time -+swift:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time -+swift:S1188 # Closures should not have too many lines. Used by Quality-time -+swift:S2042 # Classes should not have too many lines of code. Used by Quality-time -#end please ensure every rule ends with a new line character diff --git a/rules/ts.txt b/rules/ts.txt deleted file mode 100644 index e3c6877..0000000 --- a/rules/ts.txt +++ /dev/null @@ -1,11 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+typescript:S109 # Magic number; NOT used by Quality-time -+typescript:S104 # File length; NOT used by Quality-time -+typescript:S106 # Console logging; NOT used by Quality-time -+typescript:S107|maximumFunctionParameters=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters) -+typescript:S1067 # Expression too complex; NOT used by Quality-time -+typescript:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units) -+typescript:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+typescript:S4204 # The "any" type should not be used; NOT used by Quality-time --typescript:S4328 # reason: the rule does not recognize 'local' imports -#end please ensure every rule ends with a new line character diff --git a/rules/vbnet.txt b/rules/vbnet.txt deleted file mode 100644 index c1e837e..0000000 --- a/rules/vbnet.txt +++ /dev/null @@ -1,9 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+vbnet:S1541|maximumFunctionComplexityThreshold=10 # Too complex function, procedure or property; Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units) -+vbnet:S1067 # Expression too complex; NOT used by Quality-time -+vbnet:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters) -+vbnet:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+vbnet:S104 # Files should not have too many lines of code. Used by Quality-time -+vbnet:S1151 # Select Case clauses should not have too many lines of code. Used by Quality-time -# Missing: method length, NoSonar, too many parameters, commented loc -#end please ensure every rule ends with a new line character diff --git a/rules/web.txt b/rules/web.txt deleted file mode 100644 index 9c01c80..0000000 --- a/rules/web.txt +++ /dev/null @@ -1,6 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+Web:ComplexityCheck # NOT used by Quality-time. Rule is deprecated, see https://rules.sonarsource.com/html/RSPEC-1908?search=complexity -+Web:LongJavaScriptCheck # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units) -+Web:AvoidCommentedOutCodeCheck # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code) -+Web:FileLengthCheck # Files should not have too many lines. Used by Quality-time -#end please ensure every rule ends with a new line character diff --git a/rules/yaml.txt b/rules/yaml.txt deleted file mode 100644 index 4deb1c6..0000000 --- a/rules/yaml.txt +++ /dev/null @@ -1,50 +0,0 @@ -+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default -+ansible:ANSIBLE0002 -+ansible:ANSIBLE0004 -+ansible:ANSIBLE0005 -+ansible:ANSIBLE0008 -+ansible:ANSIBLE0009 -+ansible:ANSIBLE0010 -+ansible:ANSIBLE0011 -+ansible:E101 -+ansible:E102 -+ansible:E103 -+ansible:E104 -+ansible:E105 -+ansible:E203 -+ansible:E205 -+ansible:E206 -+ansible:E301 -+ansible:E302 -+ansible:E303 -+ansible:E304 -+ansible:E305 -+ansible:E401 -+ansible:E403 -+ansible:E404 -+ansible:E405 -+ansible:E501 -+ansible:E503 -+ansible:E504 -+ansible:E601 -+ansible:E602 -+yaml:BracesCheck|max-spaces-inside=1;max-spaces-inside-empty=-1;min-spaces-inside-empty=-1;min-spaces-inside=1 -+yaml:BracketsCheck|max-spaces-inside=0;max-spaces-inside-empty=-1;min-spaces-inside-empty=-1;min-spaces-inside=0 -+yaml:ColonsCheck|max-spaces-before=0;max-spaces-after=1 -+yaml:CommasCheck|max-spaces-before=0;max-spaces-after=1;min-spaces-after=1 -+yaml:CommentsCheck|require-starting-space=true;min-spaces-from-content=2 -+yaml:CommentsIndentationCheck -+yaml:DocumentStartCheck|present=true -+yaml:EmptyLinesCheck|max=2;max-start=0;max-end=0 -+yaml:EmptyValuesCheck|forbid-in-flow-mappings=false;forbid-in-block-mappings=false -+yaml:HyphensCheck|max-spaces-after=1 -+yaml:IndentationCheck|check-multi-line-strings=false;spaces=consistent;indent-sequences=true -+yaml:KeyDuplicatesCheck -+yaml:LineLengthCheck|allow-non-breakable-words=true;max=130;allow-non-breakable-inline-mappings=true -+yaml:NewLineAtEndOfFileCheck -+yaml:NewLinesCheck|type=unix -+yaml:OctalValuesCheck|forbid-implicit-octal=false;forbid-explicit-octal=false -+yaml:ParsingErrorCheck -+yaml:TrailingSpacesCheck --yaml:TruthyCheck -#end please ensure every rule ends with a new line character diff --git a/src/config.json b/src/config.json new file mode 100644 index 0000000..1f4f9eb --- /dev/null +++ b/src/config.json @@ -0,0 +1,211 @@ +{ + "rules_version": 20231222, + "plugins": [ + "https://github.com/checkstyle/sonar-checkstyle/releases/download/10.12.5/checkstyle-sonar-plugin-10.12.5.jar", + "https://github.com/dependency-check/dependency-check-sonar-plugin/releases/download/4.0.1/sonar-dependency-check-plugin-4.0.1.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.9.1/sonar-yaml-plugin-1.9.1.jar", + "https://github.com/spotbugs/sonar-findbugs/releases/download/4.2.6/sonar-findbugs-plugin-4.2.6.jar", + "https://github.com/vaulttec/sonar-auth-oidc/releases/download/v2.1.1/sonar-auth-oidc-plugin-2.1.1.jar" + ], + "profiles": { + "yaml": { + "plugin_name": "sonar-ansible-plugin", + "plugin_external": true, + "version": "ansible-profile-v2.5.1" + }, + "cs": { + "plugin_name": "csharp-plugin", + "version": "cs-profile-v9.13.0" + }, + "java": { + "plugin_name": "java-plugin", + "version": "java-profile-v7.27.1" + }, + "js": { + "plugin_name": "javascript-plugin", + "version": "js-profile-v10.9.0" + }, + "kotlin": { + "plugin_name": "kotlin-plugin", + "version": "kotlin-profile-v2.18.0" + }, + "py": { + "plugin_name": "python-plugin", + "version": "py-profile-v4.10.0" + }, + "swift": { + "plugin_name": "swift-plugin", + "version": "swift-profile-v4.11.0" + }, + "ts": { + "plugin_name": "javascript-plugin", + "version": "ts-profile-v10.9.0" + }, + "vbnet": { + "plugin_name": "vbnet-plugin", + "version": "vbnet-profile-v9.13.0" + }, + "web": { + "plugin_name": "html-plugin", + "version": "web-profile-v3.11.0" + } + }, + "rules": { + "cs": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+csharpsquid:S104 # NCSS; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+csharpsquid:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+csharpsquid:S125 # Commented code; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", + "+csharpsquid:S134 # Depth of nesting; NOT used by Quality-time", + "+csharpsquid:S1067 # Too complex expression; NOT used by Quality-time", + "+csharpsquid:S109 # Magic numbers; NOT used by Quality-time", + "+csharpsquid:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+csharpsquid:S1309 # Violation suppression; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+csharpsquid:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+csharpsquid:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time" + ], + "java": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+java:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+java:NoSonar # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S1309 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S1310 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S1315 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S1067 # Expression too complex; NOT used by Quality-time", + "+java:S109 # Magic numbers; NOT used by Quality-time", + "+java:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+java:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+java:S125 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", + "+java:S104 # Files should not have too many lines of code. Used by Quality-time", + "+java:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time", + "+java:S1188 # Anonymous classes should not have too many lines. Used by Quality-time", + "+java:S2972 # Inner classes should not have too many lines of code. Used by Quality-time", + "+java:S5612 # Lambdas should not have too many lines. Used by Quality-time" + ], + "js": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+javascript:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+javascript:S134 # NOT used by Quality-time", + "+javascript:S1067 # Expression too complex; NOT used by Quality-time", + "+javascript:S106 # Console logging should not be used; NOT used by Quality-time", + "+javascript:S107|maximumFunctionParameters=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+javascript:S109 # Magic numbers; NOT used by Quality-time", + "+javascript:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+javascript:S125 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", + "+javascript:S104 # Files should not have too many lines of code. Used by Quality-time", + "# Missing: NoSonar, NCSS, Parameters" + ], + "kotlin": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+kotlin:S1067 # Expression too complex; NOT used by Quality-time", + "+kotlin:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+kotlin:S107|Max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+kotlin:S104 # Files should not have too many lines of code. Used by Quality-time", + "+kotlin:S1151 # When clauses should not have too many lines of code. Used by Quality-time", + "+kotlin:S5612 # Lambdas should not have too many lines. Used by Quality-time" + ], + "py": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+python:S104 # Too many lines of code in file; NOT used by Quality-time", + "+python:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+python:NoSonar # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+python:S125 # Commented code; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", + "+python:S134 # Too deep nesting; NOT used by Quality-time", + "+python:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+python:FunctionComplexity|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)" + ], + "swift": [ + "+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)", + "+swift:S104 # Files should not have too many lines of code. Used by Quality-time", + "+swift:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time", + "+swift:S1188 # Closures should not have too many lines. Used by Quality-time", + "+swift:S2042 # Classes should not have too many lines of code. Used by Quality-time" + ], + "ts": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+typescript:S109 # Magic number; NOT used by Quality-time", + "+typescript:S104 # File length; NOT used by Quality-time", + "+typescript:S106 # Console logging; NOT used by Quality-time", + "+typescript:S107|maximumFunctionParameters=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+typescript:S1067 # Expression too complex; NOT used by Quality-time", + "+typescript:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+typescript:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+typescript:S4204 # The 'any' type should not be used; NOT used by Quality-time", + "-typescript:S4328 # reason: the rule does not recognize 'local' imports" + ], + "vbnet": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+vbnet:S1541|maximumFunctionComplexityThreshold=10 # Too complex function, procedure or property; Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+vbnet:S1067 # Expression too complex; NOT used by Quality-time", + "+vbnet:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+vbnet:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+vbnet:S104 # Files should not have too many lines of code. Used by Quality-time", + "+vbnet:S1151 # Select Case clauses should not have too many lines of code. Used by Quality-time", + "# Missing: method length, NoSonar, too many parameters, commented loc" + ], + "web": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+Web:ComplexityCheck # NOT used by Quality-time. Rule is deprecated, see https://rules.sonarsource.com/html/RSPEC-1908?search=complexity", + "+Web:LongJavaScriptCheck # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+Web:AvoidCommentedOutCodeCheck # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", + "+Web:FileLengthCheck # Files should not have too many lines. Used by Quality-time" + ], + "yaml": [ + "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+ansible:ANSIBLE0002", + "+ansible:ANSIBLE0004", + "+ansible:ANSIBLE0005", + "+ansible:ANSIBLE0008", + "+ansible:ANSIBLE0009", + "+ansible:ANSIBLE0010", + "+ansible:ANSIBLE0011", + "+ansible:E101", + "+ansible:E102", + "+ansible:E103", + "+ansible:E104", + "+ansible:E105", + "+ansible:E203", + "+ansible:E205", + "+ansible:E206", + "+ansible:E301", + "+ansible:E302", + "+ansible:E303", + "+ansible:E304", + "+ansible:E305", + "+ansible:E401", + "+ansible:E403", + "+ansible:E404", + "+ansible:E405", + "+ansible:E501", + "+ansible:E503", + "+ansible:E504", + "+ansible:E601", + "+ansible:E602", + "+yaml:BracesCheck|max-spaces-inside=1;max-spaces-inside-empty=-1;min-spaces-inside-empty=-1;min-spaces-inside=1", + "+yaml:BracketsCheck|max-spaces-inside=0;max-spaces-inside-empty=-1;min-spaces-inside-empty=-1;min-spaces-inside=0", + "+yaml:ColonsCheck|max-spaces-before=0;max-spaces-after=1", + "+yaml:CommasCheck|max-spaces-before=0;max-spaces-after=1;min-spaces-after=1", + "+yaml:CommentsCheck|require-starting-space=true;min-spaces-from-content=2", + "+yaml:CommentsIndentationCheck", + "+yaml:DocumentStartCheck|present=true", + "+yaml:EmptyLinesCheck|max=2;max-start=0;max-end=0", + "+yaml:EmptyValuesCheck|forbid-in-flow-mappings=false;forbid-in-block-mappings=false", + "+yaml:HyphensCheck|max-spaces-after=1", + "+yaml:IndentationCheck|check-multi-line-strings=false;spaces=consistent;indent-sequences=true", + "+yaml:KeyDuplicatesCheck", + "+yaml:LineLengthCheck|allow-non-breakable-words=true;max=130;allow-non-breakable-inline-mappings=true", + "+yaml:NewLineAtEndOfFileCheck", + "+yaml:NewLinesCheck|type=unix", + "+yaml:OctalValuesCheck|forbid-implicit-octal=false;forbid-explicit-octal=false", + "+yaml:ParsingErrorCheck", + "+yaml:TrailingSpacesCheck", + "-yaml:TruthyCheck" + ] + } +} diff --git a/plugins/install-plugins.sh b/src/install-plugins.sh old mode 100755 new mode 100644 similarity index 83% rename from plugins/install-plugins.sh rename to src/install-plugins.sh index 67abcfa..e099a17 --- a/plugins/install-plugins.sh +++ b/src/install-plugins.sh @@ -1,6 +1,6 @@ #!/bin/bash -cwd="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +plugin_list=$(jq -r ".plugins[]?" /src/config.json) plugin_dir="/opt/sonarqube/extensions/plugins" # Download plugins @@ -11,7 +11,7 @@ while read -r plugin; do echo "Error downloading ${plugin}" exit $rtn fi -done < "${cwd}"/plugin-list +done <<< "${plugin_list}" # Check if unzip required for file in "${plugin_dir}"/*; do diff --git a/start-with-profile.sh b/src/start-with-profile.sh similarity index 84% rename from start-with-profile.sh rename to src/start-with-profile.sh index 042240b..8965679 100644 --- a/start-with-profile.sh +++ b/src/start-with-profile.sh @@ -51,7 +51,7 @@ function waitForSonarUp { echo "ERROR: Failed to start Sonar within ${timeout} seconds" exit 1 fi - status=$(curl -s -f "${BASE_URL}/api/system/status" | jq -r '.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)) @@ -151,7 +151,7 @@ function createProfile { local profileName=$1 local baseProfileName=$2 local language=$3 - local rulesFilename="/tmp/rules/${language}.txt" + rules_list=$(jq -r ".rules.${language}[]?" /src/config.json) # create profile # curlAdmin -X POST "$BASE_URL/api/qualityprofiles/create?name=$profileName&language=$language" @@ -165,23 +165,20 @@ function createProfile { profileKey=$(getProfileKey "${profileName}" "${language}") echo "The profile '${profileName}' of '${language}' has the key '${profileKey}'" - if [[ -f "${rulesFilename}" ]]; then + while read -r ruleLine ; do # activate and deactivate rules in new profile - while read -r ruleLine || [ -n "${line}" ]; do - # Each line contains: - # (+|-)types=comma-seperated,list-of-types # comment - # or: (+|-)ruleId[|parameter=value] # comment - # Examples: - # +cs:1032 # some comment - # +types=SECURITY_HOTSPOT,VULNERABILITY # some comment - IFS='#';ruleSplit=("${ruleLine}");unset IFS; - rule="${ruleSplit[0]}" + # Each line contains: + # (+|-)types=comma-seperated,list-of-types # comment + # or: (+|-)ruleId[|parameter=value] # comment + # Examples: + # +cs:1032 # some comment + # +types=SECURITY_HOTSPOT,VULNERABILITY # some comment + IFS='#';ruleSplit=("${ruleLine}");unset IFS; + rule="${ruleSplit[0]}" - processRule "${rule}" "${profileKey}" "${language}" - - done < "${rulesFilename}" - fi + processRule "${rule}" "${profileKey}" "${language}" + done <<< "${rules_list}" # if the PROJECT_RULES environment variable is defined and not empty, create a custom project profile echo "Project specific rules = ${PROJECT_RULES}" @@ -260,18 +257,14 @@ changeDefaultAdminPassword testAdminCredentials # (Re-)create the ICTU profiles -RULES_VERSION=20231222 -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.13.0-${RULES_VERSION}" "Sonar%20way" "cs" # image csharp-plugin -createProfile "ictu-java-profile-v7.27.1-${RULES_VERSION}" "Sonar%20way" "java" # image java-plugin -createProfile "ictu-js-profile-v10.9.0-${RULES_VERSION}" "Sonar%20way" "js" # image javascript-plugin -createProfile "ictu-kotlin-profile-v2.18.0-${RULES_VERSION}" "Sonar%20way" "kotlin" # image kotlin-plugin -createProfile "ictu-py-profile-v4.10.0-${RULES_VERSION}" "Sonar%20way" "py" # image python-plugin -createProfile "ictu-swift-profile-v4.11.0-${RULES_VERSION}" "Sonar%20way" "swift" # image swift-plugin -createProfile "ictu-ts-profile-v10.9.0-${RULES_VERSION}" "Sonar%20way" "ts" # image javascript-plugin -createProfile "ictu-vbnet-profile-v9.13.0-${RULES_VERSION}" "Sonar%20way" "vbnet" # image vbnet-plugin -createProfile "ictu-web-profile-v3.11.0-${RULES_VERSION}" "Sonar%20way" "web" # image html-plugin +rules_version=$(jq -r ".rules_version" /src/config.json) +echo "*** Start processing rules for version ${rules_version} ***" +language_profiles=$(jq -r ".profiles | keys[]?" /src/config.json) +for language_name in ${language_profiles}; do + profile_version=$(jq -r ".profiles.${language_name}.version" /src/config.json) + profile_name="ictu-${profile_version}-${rules_version}" + createProfile "${profile_name}" "Sonar%20way" "${language_name}" +done echo "*** Finished processing rules ***" echo "" From 8d84d1a68ca5dd264904546202d0ac7d7d31155c Mon Sep 17 00:00:00 2001 From: wkoot <3715211+wkoot@users.noreply.github.com> Date: Wed, 28 Feb 2024 22:34:43 +0100 Subject: [PATCH 5/6] Test based on config data --- .github/workflows/docker-image.yml | 2 +- docker/docker-compose.ci.yml | 2 +- src/config.json | 92 ++++++++++---------- tests/test_functional.py | 130 +++++++++++++++++++++++++++++ tests/test_smoke.py | 38 --------- 5 files changed, 178 insertions(+), 86 deletions(-) create mode 100644 tests/test_functional.py delete mode 100644 tests/test_smoke.py diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 6f83912..882ca3d 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -9,7 +9,7 @@ on: env: CODE: "PROJ1" - RULES: "+csharpsquid:S104;-ts:S1561" + RULES: "+csharpsquid:S104;-ts:S1561;+Web:WhiteSpaceAroundCheck" jobs: build: diff --git a/docker/docker-compose.ci.yml b/docker/docker-compose.ci.yml index 9f40cc1..bad45af 100644 --- a/docker/docker-compose.ci.yml +++ b/docker/docker-compose.ci.yml @@ -11,7 +11,7 @@ services: SONAR_JDBC_PASSWORD: "sonar_pass" SONARQUBE_PASSWORD: "admin123" PROJECT_CODE: "PROJ1" - PROJECT_RULES: "+csharpsquid:S104;-ts:S1561" + PROJECT_RULES: "+csharpsquid:S104;-ts:S1561;+Web:WhiteSpaceAroundCheck" db: environment: diff --git a/src/config.json b/src/config.json index 1f4f9eb..ea3933a 100644 --- a/src/config.json +++ b/src/config.json @@ -53,111 +53,111 @@ }, "rules": { "cs": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+types=SECURITY_HOTSPOT,VULNERABILITY", "+csharpsquid:S104 # NCSS; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+csharpsquid:S1067 # Too complex expression; NOT used by Quality-time", "+csharpsquid:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+csharpsquid:S109 # Magic numbers; NOT used by Quality-time", + "+csharpsquid:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time", "+csharpsquid:S125 # Commented code; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", + "+csharpsquid:S1309 # Violation suppression; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", "+csharpsquid:S134 # Depth of nesting; NOT used by Quality-time", - "+csharpsquid:S1067 # Too complex expression; NOT used by Quality-time", - "+csharpsquid:S109 # Magic numbers; NOT used by Quality-time", "+csharpsquid:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", - "+csharpsquid:S1309 # Violation suppression; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", - "+csharpsquid:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", - "+csharpsquid:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time" + "+csharpsquid:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)" ], "java": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", - "+java:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+types=SECURITY_HOTSPOT,VULNERABILITY", "+java:NoSonar # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", - "+java:S1309 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", - "+java:S1310 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", - "+java:S1315 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S104 # Files should not have too many lines of code. Used by Quality-time", "+java:S1067 # Expression too complex; NOT used by Quality-time", - "+java:S109 # Magic numbers; NOT used by Quality-time", - "+java:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", "+java:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", - "+java:S125 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", - "+java:S104 # Files should not have too many lines of code. Used by Quality-time", + "+java:S109 # Magic numbers; NOT used by Quality-time", "+java:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time", "+java:S1188 # Anonymous classes should not have too many lines. Used by Quality-time", + "+java:S125 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", + "+java:S1309 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S1310 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S1315 # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", + "+java:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+java:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", "+java:S2972 # Inner classes should not have too many lines of code. Used by Quality-time", "+java:S5612 # Lambdas should not have too many lines. Used by Quality-time" ], "js": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", - "+javascript:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", - "+javascript:S134 # NOT used by Quality-time", - "+javascript:S1067 # Expression too complex; NOT used by Quality-time", + "+types=SECURITY_HOTSPOT,VULNERABILITY", + "+javascript:S104 # Files should not have too many lines of code. Used by Quality-time", "+javascript:S106 # Console logging should not be used; NOT used by Quality-time", + "+javascript:S1067 # Expression too complex; NOT used by Quality-time", "+javascript:S107|maximumFunctionParameters=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", "+javascript:S109 # Magic numbers; NOT used by Quality-time", - "+javascript:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", "+javascript:S125 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", - "+javascript:S104 # Files should not have too many lines of code. Used by Quality-time", + "+javascript:S134 # NOT used by Quality-time", + "+javascript:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+javascript:S1541|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", "# Missing: NoSonar, NCSS, Parameters" ], "kotlin": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+types=SECURITY_HOTSPOT,VULNERABILITY", + "+kotlin:S104 # Files should not have too many lines of code. Used by Quality-time", "+kotlin:S1067 # Expression too complex; NOT used by Quality-time", - "+kotlin:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", "+kotlin:S107|Max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", - "+kotlin:S104 # Files should not have too many lines of code. Used by Quality-time", "+kotlin:S1151 # When clauses should not have too many lines of code. Used by Quality-time", + "+kotlin:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", "+kotlin:S5612 # Lambdas should not have too many lines. Used by Quality-time" ], "py": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+types=SECURITY_HOTSPOT,VULNERABILITY", + "+python:FunctionComplexity|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+python:NoSonar # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", "+python:S104 # Too many lines of code in file; NOT used by Quality-time", "+python:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", - "+python:NoSonar # Used by Quality-time to report on suppressed violations (https://quality-time.readthedocs.io/en/latest/reference.html#suppressed-violations)", "+python:S125 # Commented code; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", "+python:S134 # Too deep nesting; NOT used by Quality-time", - "+python:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", - "+python:FunctionComplexity|maximumFunctionComplexityThreshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)" + "+python:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)" ], "swift": [ - "+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)", + "+types=SECURITY_HOTSPOT,VULNERABILITY", + "+swift:S104 # Files should not have too many lines of code. Used by Quality-time", "+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)", - "+swift:S104 # Files should not have too many lines of code. Used by Quality-time", "+swift:S1151 # Switch case clauses should not have too many lines of code. Used by Quality-time", "+swift:S1188 # Closures should not have too many lines. Used by Quality-time", + "+swift:S125 # Used by Quality-time (https://github.com/ICTU/quality-time/blob/master/docs/METRICS_AND_SOURCES.md#commented-out-code-from-sonarqube)", + "+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: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:S2042 # Classes should not have too many lines of code. Used by Quality-time" ], "ts": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", - "+typescript:S109 # Magic number; NOT used by Quality-time", + "+types=SECURITY_HOTSPOT,VULNERABILITY", "+typescript:S104 # File length; NOT used by Quality-time", "+typescript:S106 # Console logging; NOT used by Quality-time", - "+typescript:S107|maximumFunctionParameters=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", "+typescript:S1067 # Expression too complex; NOT used by Quality-time", - "+typescript:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+typescript:S107|maximumFunctionParameters=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", + "+typescript:S109 # Magic number; NOT used by Quality-time", "+typescript:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+typescript:S1541|Threshold=10 # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", "+typescript:S4204 # The 'any' type should not be used; NOT used by Quality-time", "-typescript:S4328 # reason: the rule does not recognize 'local' imports" ], "vbnet": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", - "+vbnet:S1541|maximumFunctionComplexityThreshold=10 # Too complex function, procedure or property; Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", + "+types=SECURITY_HOTSPOT,VULNERABILITY", + "+vbnet:S104 # Files should not have too many lines of code. Used by Quality-time", "+vbnet:S1067 # Expression too complex; NOT used by Quality-time", "+vbnet:S107|max=5 # Too many parameters; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#many-parameters)", - "+vbnet:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", - "+vbnet:S104 # Files should not have too many lines of code. Used by Quality-time", "+vbnet:S1151 # Select Case clauses should not have too many lines of code. Used by Quality-time", + "+vbnet:S138|max=20 # Methods with too many lines; used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+vbnet:S1541|maximumFunctionComplexityThreshold=10 # Too complex function, procedure or property; Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#complex-units)", "# Missing: method length, NoSonar, too many parameters, commented loc" ], "web": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", - "+Web:ComplexityCheck # NOT used by Quality-time. Rule is deprecated, see https://rules.sonarsource.com/html/RSPEC-1908?search=complexity", - "+Web:LongJavaScriptCheck # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)", + "+types=SECURITY_HOTSPOT,VULNERABILITY", "+Web:AvoidCommentedOutCodeCheck # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#commented-out-code)", - "+Web:FileLengthCheck # Files should not have too many lines. Used by Quality-time" + "+Web:ComplexityCheck # NOT used by Quality-time. Rule is deprecated, see https://rules.sonarsource.com/html/RSPEC-1908?search=complexity", + "+Web:FileLengthCheck # Files should not have too many lines. Used by Quality-time", + "+Web:LongJavaScriptCheck # Used by Quality-time (https://quality-time.readthedocs.io/en/latest/reference.html#long-units)" ], "yaml": [ - "+types=SECURITY_HOTSPOT,VULNERABILITY # Enable these types by default", + "+types=SECURITY_HOTSPOT,VULNERABILITY", "+ansible:ANSIBLE0002", "+ansible:ANSIBLE0004", "+ansible:ANSIBLE0005", diff --git a/tests/test_functional.py b/tests/test_functional.py new file mode 100644 index 0000000..4c98500 --- /dev/null +++ b/tests/test_functional.py @@ -0,0 +1,130 @@ +from json import loads +from os import getenv +from unittest import TestCase, skipUnless + +import requests +from sonarqube import SonarQubeClient + +PROJECT_CODE = getenv("PROJECT_CODE") +PROJECT_RULES = getenv("PROJECT_RULES") +CONFIG_FILE = getenv("CONFIG_FILE", "/src/config.json") + + +class FunctionalTest(TestCase): + @classmethod + def setUpClass(cls): + """Expose sonar api and credentials to tests.""" + with open(CONFIG_FILE, "r") as config_file: + cls.config_json = loads(config_file.read()) + sonar_port = getenv("SONAR_PORT", "9000") + sonar_base_url = f"http://localhost:{sonar_port}" + sonar_pass = getenv("SONARQUBE_PASSWORD", "admin") + cls.sonar_client = SonarQubeClient(sonarqube_url=sonar_base_url, username="admin", password=sonar_pass) + cls.sonar_api = f"{sonar_base_url}/api" + cls.sonar_auth = ("admin", sonar_pass) + + def _search_profiles(self, **kwargs): + """Convenience wrapper for sonar api quality profile search.""" + return self.sonar_client.qualityprofiles.search_quality_profiles(**kwargs) + + def _search_rules(self, **kwargs): + """Convenience wrapper for sonar api rule search.""" + return self.sonar_client.rules.search_rules(**kwargs) + + def test_sonar_way_profile_remains(self): + """Check that the 'Sonar way' profile remains when a profile is defined for the language.""" + java_profiles = self._search_profiles(language="java") + self.assertIn("Sonar way", [profile["name"] for profile in java_profiles["profiles"]]) + version_profile = f"ictu-{self.config_json['profiles']['java']['version']}-{self.config_json['rules_version']}" + self.assertIn(version_profile, [profile["name"] for profile in java_profiles["profiles"]]) + + @skipUnless(PROJECT_CODE, "PROJECT_CODE was not passed") + @skipUnless(PROJECT_RULES, "PROJECT_RULES was not passed") + def test_project_override_profile(self): + """Check that overridden rule activation is applied.""" + overridden_key = "Web:WhiteSpaceAroundCheck" + self.assertTrue(any([rule_line == f"+{overridden_key}" for rule_line in PROJECT_RULES.split(";")])) + + version_profile = f"ictu-{self.config_json['profiles']['web']['version']}-{self.config_json['rules_version']}" + web_profiles = self._search_profiles( + defaults="true", language="web", qualityProfile=f"{PROJECT_CODE}-{version_profile}" + ) # also verify that the overridden profile is the default + web_profile_key = next(profile["key"] for profile in web_profiles["profiles"]) + web_rule = self._search_rules(activation="true", qprofile=web_profile_key, rule_key=overridden_key) + self.assertEqual(1, web_rule["total"]) + + # Verify that it indeed differs from the custom profile + web_profiles = self._search_profiles(defaults="false", language="web", qualityProfile=version_profile) + web_profile_key = next(profile["key"] for profile in web_profiles["profiles"]) + web_rule = self._search_rules(activation="false", qprofile=web_profile_key, rule_key=overridden_key) + self.assertEqual(1, web_rule["total"]) + + def test_type_profile(self): + """Check that custom profile rule type activation is applied.""" + self.assertIn("types=", self.config_json["rules"]["web"][0]) + overridden_key = "Web:AvoidHtmlCommentCheck" + self.assertFalse(next(overridden_key in rule_line for rule_line in self.config_json["rules"]["web"])) + + version_profile = f"ictu-{self.config_json['profiles']['web']['version']}-{self.config_json['rules_version']}" + web_profiles = self._search_profiles(language="web", qualityProfile=version_profile) + web_profile_key = next(profile["key"] for profile in web_profiles["profiles"]) + web_rule = self._search_rules(activation="true", qprofile=web_profile_key, rule_key=overridden_key) + self.assertEqual(1, web_rule["total"]) + + # Verify that it indeed differs from the Sonar way + sonar_way_web = self._search_profiles(language="web", qualityProfile="Sonar way") + sonar_way_key = next(p["key"] for p in sonar_way_web["profiles"]) + sonar_way_rule = self._search_rules(activation="false", qprofile=sonar_way_key, rule_key=overridden_key) + self.assertEqual(1, sonar_way_rule["total"]) + + def test_rule_params_in_profile(self): + """Check that custom profile rule params are applied.""" + cs_param_rule_lines = [rule_line for rule_line in self.config_json["rules"]["cs"] if "|" in rule_line] + self.assertNotEqual([], cs_param_rule_lines) + + version_profile = f"ictu-{self.config_json['profiles']['cs']['version']}-{self.config_json['rules_version']}" + cs_profile_search = self._search_profiles(language="cs", qualityProfile=version_profile) + self.assertEqual(1, len(cs_profile_search["profiles"])) + + # Fetch changelog api with requests, because library does not expose it + changelog_api = f"{self.sonar_api}/qualityprofiles/changelog" + change_history_params = {"language": "cs", "qualityProfile": version_profile, "ps": 500} + api_result = requests.get(changelog_api, auth=self.sonar_auth, params=change_history_params).json() + self.assertGreater(change_history_params["ps"], api_result["total"]) + + # Verify that each param override has a corresponding changelog event + profile_changes = api_result["events"] + for cs_rule_line in cs_param_rule_lines: + rule_key, rule_params_str = cs_rule_line[1:].split()[0].split("|") + rule_changes = [change for change in profile_changes if change["ruleKey"] == rule_key] + for rule_param_str in rule_params_str.split(";"): + rule_params = rule_param_str.split("=") + param_dict = {rule_params[0]: rule_params[1]} + self.assertTrue(next( + param_dict.items() <= rule_change.get('params', {}).items() for rule_change in rule_changes + )) + + # Verify that it indeed differs from the Sonar way + self.assertTrue(next(event for event in profile_changes if event["action"] == "UPDATED")) + + def test_profile_rule_deactivation(self): + """Check that custom profile rule deactivation is applied.""" + ts_rule_lines = [rule_line for rule_line in self.config_json["rules"]["ts"] if "types=" not in rule_line] + self.assertTrue(any([rule_line.startswith("-") for rule_line in ts_rule_lines])) + self.assertTrue(any([rule_line.startswith("+") for rule_line in ts_rule_lines])) + + version_profile = f"ictu-{self.config_json['profiles']['ts']['version']}-{self.config_json['rules_version']}" + ts_profile_search = self._search_profiles(language="ts", qualityProfile=version_profile) + ts_profile_key = next(profile["key"] for profile in ts_profile_search["profiles"]) + + for ts_rule_line in ts_rule_lines: + activation = "yes" if ts_rule_line[0] == "+" else "no" + rule_key = ts_rule_line[1:].split()[0].split("|")[0] + ts_rule = self._search_rules(activation=activation, qprofile=ts_profile_key, rule_key=rule_key) + self.assertEqual(1, ts_rule["total"]) + + # Verify that it indeed differs from the Sonar way + sonar_way_ts = self._search_profiles(language="ts", qualityProfile="Sonar way") + sonar_way_key = next(p["key"] for p in sonar_way_ts["profiles"]) + sonar_way_rule = self._search_rules(qprofile=sonar_way_key, rule_key="swift:S104") + self.assertEqual(0, sonar_way_rule["total"]) # is not listed as a disabled key diff --git a/tests/test_smoke.py b/tests/test_smoke.py deleted file mode 100644 index f80a9db..0000000 --- a/tests/test_smoke.py +++ /dev/null @@ -1,38 +0,0 @@ -from os import getenv -from unittest import TestCase, skipUnless - -from sonarqube import SonarQubeClient - -PROJECT_CODE = getenv("PROJECT_CODE") -PROJECT_RULES = getenv("PROJECT_RULES") - - -class SonarTest(TestCase): - def setUp(self) -> None: - sonar_port = getenv("SONAR_PORT", "9000") - sonar_base_url = f"http://localhost:{sonar_port}" - sonar_pass = getenv("SONARQUBE_PASSWORD", "admin") - self.sonar_client = SonarQubeClient(sonarqube_url=sonar_base_url, username="admin", password=sonar_pass) - - def test_java_profile(self): - java_quality_profiles = self.sonar_client.qualityprofiles.search_quality_profiles(language="java") - java_profile_names = [profile["name"] for profile in java_quality_profiles["profiles"]] - self.assertIn("Sonar way", java_profile_names) - - @skipUnless(PROJECT_CODE, "PROJECT_CODE was not passed") - def test_csharpsquid_profile(self): - search_result = self.sonar_client.qualityprofiles.search_quality_profiles( - defaults="true", language="cs", qualityProfile=f"{PROJECT_CODE}-ictu-cs-profile-v9.13.0-20231222" - ) - self.assertEqual(len(search_result['profiles']), 1) - cs_profile_key = search_result['profiles'][0]['key'] - self.assertIsNotNone(cs_profile_key) # TODO - check activated rules within profile instead - - @skipUnless(PROJECT_CODE, "PROJECT_CODE was not passed") - def test_ts_profile(self): - search_result = self.sonar_client.qualityprofiles.search_quality_profiles( - defaults="true", language="ts", qualityProfile=f"{PROJECT_CODE}-ictu-ts-profile-v10.9.0-20231222" - ) - self.assertEqual(len(search_result['profiles']), 1) - ts_profile_key = search_result['profiles'][0]['key'] - self.assertIsNotNone(ts_profile_key) # TODO - check activated rules within profile instead From 0a69a554e340b2a0a14b105e5692233f7328d629 Mon Sep 17 00:00:00 2001 From: wkoot <3715211+wkoot@users.noreply.github.com> Date: Tue, 5 Mar 2024 13:12:47 +0100 Subject: [PATCH 6/6] Update docs --- MAINTENANCE.md | 30 +++++++++++++++++------------- README.md | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 5dbfd26..8e382f0 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -4,10 +4,10 @@ ## Version upgrade workflow 1. Update `Dockerfile`s with the new version of SonarQube -1. Update [external plugins](https://github.com/ICTU/sonar/blob/master/plugins/plugin-list) -1. Create profiles based on the internal plugin versions in [start-with-profile.sh](https://github.com/ICTU/sonar/blob/rules-update/start-with-profile.sh) +1. Update external plugins in the [config.json](https://github.com/ICTU/sonar/blob/master/src/config.json) +1. Create profiles based on the internal plugin versions in the [config.json](https://github.com/ICTU/sonar/blob/master/src/config.json) 1. Obtain the base version numbers from the vanilla SonarQube image directory `/opt/sonarqube/lib/extensions`, excluding build number - 1. Update the profile version number `RULES_VERSION` if the rules have been changed + 1. Update the config rules version number `rules_version` if the rules have been changed 1. Create new version tags on github 1. `MAJOR.MINOR.PATCH` 1. `MAJOR.MINOR.PATCH-developer` @@ -16,22 +16,27 @@ ## Adding plugins -Add the url of the plugin jar-file to be installed to `plugins/plugin-list`. +Add the url of the plugin jar-file to be installed to the [config.json](https://github.com/ICTU/sonar/blob/master/src/config.json) value of `plugins`. ## Creating a new quality profile -Modify `start-with-profile.sh` and add a statement to the end of the script, such as: +Modify the [config.json](https://github.com/ICTU/sonar/blob/master/src/config.json) value of `profiles` and add a key (language as profile name) with value dictionary, such as: - createProfile "ictu-cs-profile-v6.6" "Sonar%20way" "cs" + "yaml": { + "plugin_name": "sonar-ansible-plugin", + "plugin_external": true, + "version": "ansible-profile-v2.5.1" + }, The parameters are: -* Profile name -* Base profile name -* Language (internal SonarQube language identifier) +* (key): language (internal SonarQube language identifier) +* plugin_name: name of the plugin to be used for this profile +* plugin_external: true for external plugin, false (default) when it is contained in the base container image +* version: profile version string (based on the plugin version) -## Create rules txt file from SonarQubes quality profile backup (xml) +## Create rule entries from SonarQubes quality profile backup (xml) In order to make the importing of existing profiles easier, use the transformation `profile_backup_transform.xslt`. Go to the profiles page in your SonarQube instance, backup a profile to an xml file and transform it. @@ -39,9 +44,8 @@ Go to the profiles page in your SonarQube instance, backup a profile to an xml f ## Activating or deactivating individual rules in the quality profiles -Modify the corresponding `rules/(language).txt` file. -Each line represents a rule to be activated or deactivated and has the following syntax: `(operation)(ruleId)#(comment)` -Please ensure each file ends with a new line character, otherwise the rule will not be added to the profile +Modify the corresponding [config.json](https://github.com/ICTU/sonar/blob/master/src/config.json) value of `rules[language]`. +Each entry represents a rule to be activated or deactivated and has the following syntax: `(operation)(ruleId)#(comment)` * **operation**: `+` activates a rule; `-` deactivates a rule * **ruleId**: SonarQube rule identifier diff --git a/README.md b/README.md index 46fb525..c1d0dc1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A SonarQube container image with plugins, profiles and config used at ICTU ## Creating a new quality profile -When starting the SonarQube image, new quality profiles will be automatically created for [supported languages](https://github.com/ICTU/sonar/blob/master/rules). +When starting the SonarQube image, new quality profiles will be automatically created for [supported languages](https://github.com/ICTU/sonar/blob/master/src/config.json). These newly created profiles are set to be the default profile, but can also be [extended with your own custom rules](https://docs.sonarsource.com/sonarqube/latest/instance-administration/quality-profiles/#extending-a-quality-profile). Extending the default can be done by ensuring that the current profile has a name ending with `EXTENDED` (or `extended`).