# Scan Your Code ## Provision New Project As an administrator, log in to the Linty web interface and go to **Administration > Projects > Management > Create Project** to provision your project: ![Create Project](../assets/images/scan/create-project.png) Once your project has been provisioned, update its permissions. To do so, go to **Project Setting > Permissions** and add the following role(s) to the `linty-scanner` user: * **Execute Analysis** * **Browse** (only for Private projects) ![Set Permissions](../assets/images/scan/set-permissions.png) Then, you can select which [quality profiles](rules_to_check) (set of rules) to use. ## Scan Your Code To scan your code, run the [Linty Scanner](https://hub.docker.com/r/lintyservices/linty-scanner) that is provided as a Docker image. ### Compatibility Matrix with Linty Server | [Linty Scanner](https://hub.docker.com/r/lintyservices/linty-scanner) | [Linty Server](https://hub.docker.com/r/lintyservices/linty-server) | |:---------------------------------------------------------------------:|:-------------------------------------------------------------------:| | 4.0.0 (latest) | 4.0.1 | | 3.1.0 | 3.1.0 | | 3.0.0 | 3.0.0 | | 2.1.0 | 2.1.0 | | 2.0.0 | 2.0.0 | | 1.2.0 | 1.2.0 | | 1.1.0 | 1.1.0 | ### Requirements #### Hardware * **Memory**: Usage will depend on the size of the source code to analyze. 2GB of free RAM should already allow you to analyze large projects. * **CPU**: The faster the CPUs, the faster the scan will be. So, we highly recommend you to invest on multi-core and fast CPUs. * **Disk**: Used space will depend on the size of the source code to analyze. 10GB of free space should already allow you to analyze several large projects. #### Network The only connection that is necessary is to the [Linty platform](install.md). No external connection is needed. #### Operating System Linty scans can be triggered from a machine: * Running under either Linux or Windows or Mac * With AMD or Intel or ARM processors ##### Linux Either install [Docker Engine (with containerd and Docker Compose) 23 or greater](https://docs.docker.com/engine/install/ubuntu/) or [Docker Desktop for Linux (latest version)](https://docs.docker.com/desktop/install/linux-install/). If you choose to install Docker Desktop, make sure to make it [start automatically](https://docs.docker.com/desktop/settings/linux/#general). ##### Windows Linty Scanner requires a version of Windows on which WSL 2 (Windows Subsystem for Linux) is enabled. You can watch the following videos to enable WSL on [Windows 10](https://www.youtube.com/watch?v=f1_3wg6Uvhk) or [Windows 11](https://www.youtube.com/watch?v=nARnhEkVAxY). Note that the last step (Ubuntu installation is not required). Then, install [Docker Desktop for Windows (latest version)](https://docs.docker.com/desktop/install/windows-install/). Make [Docker Desktop starts automatically](https://docs.docker.com/desktop/settings/windows/#general). Once Docker Desktop is started, make sure to [switch to Linux containers](https://learn.microsoft.com/en-us/virtualization/windowscontainers/quick-start/quick-start-windows-10-linux#run-your-first-linux-container) ##### Mac Install [Docker Desktop for Mac (latest version)](https://docs.docker.com/desktop/install/mac-install/). Make [Docker Desktop starts automatically](https://docs.docker.com/desktop/settings/mac/#general). ### Configure Linty Scan Linty provides two engines: * Linter: Read your code and check rules mainly related to maintainability. * BugFinder (part of [Linty Ultra](https://linty-services.com/pricing)): Synthesize your code and check rules mainly related to reliability and security. #### Base Configuration Add a `sonar-project.properties` file to the root of your project: ```properties # Key of the project you provisioned in the previous step sonar.projectKey=my-project-key # Project name that you want to display on the Linty web interface sonar.projectName=My Project Name # Comma-separated list of directories containing your source code (VHDL, Verilog/SystemVerilog and Tcl files). # Paths are relative to the project base directory. sonar.sources=./src ``` #### Linter Configuration ##### VHDL and Verilog/SystemVerilog Set the `sonar.hdl.topModule` property. See [Top-level Module/Entity](top_level_module). ##### Verilog/SystemVerilog Only Linty parsing of Verilog/SystemVerilog project extends [slang](https://sv-lang.com/index.html). Thus, an slang configuration file is required. Add an `slang.conf` file to the root of your project to tell Linty how to read and elaborate your project. Browse some project samples to get started: * [cv32e40p](https://github.com/Linty-Services/cv32e40p/blob/linty/slang.conf): Reading from filelist * [Ibex RISC-V Core](https://github.com/Linty-Services/ibex/blob/linty/slang.conf): Manually listing files * [UVM Core](https://github.com/Linty-Services/uvm-core/blob/linty/slang.conf) And read [slang detailed documentation](https://sv-lang.com/command-line-ref.html). #### BugFinder Configuration (requires Linty Ultra) See [BugFinder](scan_bugfinder.md). ### Run Linty Scan #### On Premise (Linux) Create a directory that will act as a cache for Linty plugins. That way, plugins will not be downloaded from your Linty server each time you run an analysis. Analyses will run faster then. ##### With Linter Engine Only Depending on the activated rules, you might have to set the `sonar.hdl.topModule` property. See [Top-level Module/Entity](top_level_module). Then, run the following Docker command: ```bash docker run \ --rm \ --user="$(id -u):$(id -g)" \ --net=host \ -e SONAR_HOST_URL="" \ -e SONAR_TOKEN="" \ -v ":/usr/src" \ -v ":/opt/sonar-scanner/.sonar/cache" \ lintyservices/linty-scanner: -Dsonar.bugfinder.enabled=false ``` ```bash # Example: Let's say that you run this Docker command from the root directory of your project. docker run \ --rm \ --user="$(id -u):$(id -g)" \ --net=host \ -e SONAR_HOST_URL="http(s)://xxx" \ -e SONAR_TOKEN="squ_xxx" \ -v "${PWD}:/usr/src" \ -v "/home/abc/.sonar/cache:/opt/sonar-scanner/.sonar/cache" \ lintyservices/linty-scanner: -Dsonar.bugfinder.enabled=false ``` ##### With both Linter and BugFinder Engines Run the following Docker command: ```bash docker run \ --rm \ --user="$(id -u):$(id -g)" \ --net=host \ -e SONAR_HOST_URL="" \ -e SONAR_TOKEN="" \ -e TABBY_CAD_LICENSE="" \ -v ":/opt/licenses/yosyshq-license.txt" \ -v ":/usr/src" \ -v ":/opt/sonar-scanner/.sonar/cache" \ lintyservices/linty-scanner: ``` ```bash # Example #1 # Let's say that: # - Your Tabby CAD (Linty Services edition) license is stored as a file at /opt/linty/my-tabby.lic # - You run this Docker command from the root directory of your project docker run \ --rm \ --user="$(id -u):$(id -g)" \ --net=host \ -e SONAR_HOST_URL="http(s)://xxx" \ -e SONAR_TOKEN="squ_xxx" \ -v "${PWD}:/usr/src" \ -v "/opt/linty/my-tabby.lic:/opt/licenses/yosyshq-license.txt" \ -v "/home/abc/.sonar/cache:/opt/sonar-scanner/.sonar/cache" \ lintyservices/linty-scanner: ``` ```bash # Example #2 # Let's say that: # - Your Tabby CAD (Linty Services edition) license is stored as an environment variable: $TABBY_CAD_LICENSE # - You run this Docker command from the root directory of your project docker run \ --rm \ --user="$(id -u):$(id -g)" \ --net=host \ -e SONAR_HOST_URL="http(s)://xxx" \ -e SONAR_TOKEN="squ_xxx" \ -e TABBY_CAD_LICENSE="$TABBY_CAD_LICENSE" \ -v "${PWD}:/usr/src" \ -v "/home/abc/.sonar/cache:/opt/sonar-scanner/.sonar/cache" \ lintyservices/linty-scanner: ``` Browse [project sample](https://github.com/Linty-Services/bugfinder-sample-on-premise). ##### Advanced usage ```bash # Run in debug mode docker run ... lintyservices/linty-scanner: -Dsonar.verbose=true ``` ```bash # Add timestamp docker run ... lintyservices/linty-scanner: | ts "[%Y-%m-%d %H:%M:%S]" ``` #### On Premise (Windows) The above **On Premise (Linux)** documentation applies for Windows with the following notes: 1. Run commands in PowerShell 2. Remove the following lines from the `docker run` command: ```shell --user="$(id -u):$(id -g)" --net=host ``` 3. Add the following line to the `docker run` command with the MAC address provided with the Linty license. Make sure to use `:` separators. ```shell --mac-address=XX:XX:XX:XX:XX:XX ``` 4. Line break in commands is `` ` `` instead of `\` 5. Double quote additional properties: `-D"sonar.bugfinder.enabled"=false` **Example:** ```shell # Let's say that: # - Your Tabby CAD (Linty Services edition) license is stored as a file at C:\Users\me\linty\my-tabby.lic # - You run this Docker command from the root directory of your project # - Your Linty cache directory is C:\Users\me\linty\cache docker run ` --rm ` --mac-address="XX:XX:XX:XX:XX:XX" ` -e SONAR_HOST_URL="http(s)://xxx" ` -e SONAR_TOKEN="squ_xxx" ` -v "${PWD}:/usr/src" ` -v "C:\Users\me\linty\my-tabby.lic:/opt/licenses/yosyshq-license.txt" ` -v "C:\Users\me\linty\cache:/opt/sonar-scanner/.sonar/cache" ` lintyservices/linty-scanner: ``` #### On Premise (Mac) The above **On Premise (Linux)** documentation applies for Mac with the following notes: 1. Remove the following line from the `docker run` command: ```shell --net=host ``` 2. Add the following line to the `docker run` command with the MAC address provided with the Linty license: ```shell --mac-address=XX:XX:XX:XX:XX:XX ``` **Example:** ```shell # Let's say that: # - Your Tabby CAD (Linty Services edition) license is stored as a file at /home/me/linty/my-tabby.lic # - You run this Docker command from the root directory of your project # - Your Linty cache directory is /home/me/linty/cache docker run \ --rm \ --user="$(id -u):$(id -g)" \ --mac-address="XX:XX:XX:XX:XX:XX" \ -e SONAR_HOST_URL="http(s)://xxx" \ -e SONAR_TOKEN="squ_xxx" \ -v "${PWD}:/usr/src" \ -v "/home/me/linty/my-tabby.lic:/opt/licenses/yosyshq-license.txt" \ -v "/home/me/linty/cache:/opt/sonar-scanner/.sonar/cache" \ lintyservices/linty-scanner: ``` #### From GitHub Create the following Actions secrets on your repository: * `LINTY_SCANNER_TOKEN`: Token of the 'linty-scanner' user * `TABBY_CAD_LICENSE`: Tabby CAD license key (only required if you have purchased [Linty Ultra](https://linty-services.com/pricing)) ##### Analyze 'main' branch only Add the following: `.github/worfklows/linty.yml` file to your project: ```yaml name: Linty on: push: branches: - main jobs: linty: name: Linty timeout-minutes: 10 runs-on: ubuntu-latest steps: - name: Git Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cache id: cache-sonar uses: actions/cache@v4 with: path: ~/.sonar/cache key: sonar restore-keys: sonar - name: Create cache directory if cache is not restored if: steps.cache-sonar.outputs.cache-hit != 'true' run: mkdir $HOME/.sonar && mkdir $HOME/.sonar/cache - name: Run Linty run: | docker run \ --rm \ --user="$(id -u):$(id -g)" \ -e SONAR_HOST_URL="http(s)://xxx" \ -e SONAR_TOKEN="${{ secrets.LINTY_SCANNER_TOKEN }}" \ -e GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" \ -e GITHUB_REPOSITORY_OWNER="$GITHUB_REPOSITORY_OWNER" \ -e GITHUB_REPOSITORY="$GITHUB_REPOSITORY" \ -e TABBY_CAD_LICENSE="$TABBY_CAD_LICENSE" \ -v "$HOME/.sonar/cache:/opt/sonar-scanner/.sonar/cache" \ -v "${PWD}:/usr/src" \ lintyservices/linty-scanner: env: TABBY_CAD_LICENSE: ${{secrets.TABBY_CAD_LICENSE}} - name: Debug if: always() uses: actions/upload-artifact@v4 with: name: debug include-hidden-files: true path: .linty/ ``` ##### Analyze all branches and pull requests Prerequisites: * Configure [GitHub connection](https://docs.sonarqube.org/latest/devops-platform-integration/github-integration/) Add the following: `.github/worfklows/linty.yml` file to your project: ```yaml name: Linty on: push: pull_request: jobs: linty: name: Linty timeout-minutes: 10 runs-on: ubuntu-latest env: SONAR_HOST_URL: http(s)://xxx steps: - name: Git Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cache id: cache-sonar uses: actions/cache@v4 with: path: $HOME/.sonar/cache key: sonar restore-keys: sonar - name: Create cache directory if cache is not restored if: steps.cache-sonar.outputs.cache-hit != 'true' run: mkdir $HOME/.sonar && mkdir $HOME/.sonar/cache - name: Set Linty Analysis parameters uses: haya14busa/action-cond@v1 id: linty_analysis_parameters with: cond: ${{ github.event.pull_request.number != '' }} if_true: -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} -Dsonar.pullrequest.base=${{ github.base_ref }} -Dsonar.pullrequest.branch=${{ github.head_ref }} if_false: -Dsonar.branch.name=${GITHUB_REF#refs/*/} - name: Run Linty run: | docker run \ --rm \ --user="$(id -u):$(id -g)" \ -e SONAR_HOST_URL=${{ env.SONAR_HOST_URL }} \ -e SONAR_TOKEN="${{ secrets.SONARQUBE_SCANNER_FOR_PRIVATE_REPOSITORIES_TOKEN }}" \ -e GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" \ -e GITHUB_REPOSITORY_OWNER="$GITHUB_REPOSITORY_OWNER" \ -e GITHUB_REPOSITORY="$GITHUB_REPOSITORY" \ -e TABBY_CAD_LICENSE="$TABBY_CAD_LICENSE" \ -v "$HOME/.sonar/cache:/opt/sonar-scanner/.sonar/cache" \ -v "${PWD}:/usr/src" \ lintyservices/linty-scanner: \ -Dsonar.qualitygate.wait=true ${{ steps.linty_analysis_parameters.outputs.value }} env: TABBY_CAD_LICENSE: ${{ secrets.TABBY_CAD_LICENSE }} - name: Debug if: always() uses: actions/upload-artifact@v4 with: name: debug include-hidden-files: true path: .linty/ ``` See fully configured project sample: * [GitHub repository](https://github.com/Linty-Services/bugfinder-sample) * [Linty Cloud project analysis](https://cloud.linty-services.com/dashboard?id=github-bugfinder-sample) * [Pull request decoration example](https://github-pr.linty-services.com/) #### From GitLab Create the following variables on your project: * `SONAR_HOST_URL`: URL of your Linty platform * `SONAR_TOKEN`: Token of the 'linty-scanner' user * `TABBY_CAD_LICENSE`: Tabby CAD license key (only required if you have purchased [Linty Ultra](https://linty-services.com/pricing)) * `CI_TABBYCAD_TOKEN`: Personal token with scope 'api' (only required if you have purchased [Linty Ultra](https://linty-services.com/pricing) and running on gitlab.com) To do so, go to **Settings > CI/CD > Variables**. ##### Analyze 'main' branch only Add the following `.gitlab-ci.yml` file to your project: ```yaml linty: image: name: lintyservices/linty-scanner: pull_policy: if-not-present variables: GIT_DEPTH: "0" SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" cache: key: "${CI_JOB_NAME}" paths: - .sonar/cache script: - sonar-scanner -Dsonar.qualitygate.wait=true artifacts: when: always paths: - .linty/ only: - main ``` ##### Analyze all branches and merge requests Prerequisites: * Configure [GitLab connection](https://docs.sonarqube.org/latest/devops-platform-integration/gitlab-integration/) Add the following `.gitlab-ci.yml` file to your project: ```yaml workflow: rules: # Analyze all merge requests and all branches that do not have a related opened merge request - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS when: never - if: $CI_COMMIT_BRANCH linty: image: name: lintyservices/linty-scanner: pull_policy: if-not-present variables: GIT_DEPTH: "0" SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" cache: key: "${CI_JOB_NAME}" paths: - .sonar/cache script: - sonar-scanner -Dsonar.qualitygate.wait=true artifacts: when: always paths: - .linty/ ``` See fully configured project sample: * [GitLab repository](https://gitlab.com/linty-services/bugfinder-sample) * [Linty Cloud project analysis](https://cloud.linty-services.com/dashboard?id=gitlab-bugfinder-sample) * [Pull request decoration example](https://gitlab-mr.linty-services.com/) ### Troubleshooting #### Linty is unable to analyze file - Caused by: org.sonar.sslr.grammar.GrammarException: The regular expression 'xxx' has led to a stack overflow error If you face the following issue: ``` ERROR: Error during SonarScanner execution org.sonar.squidbridge.api.AnalysisException: SonarQube is unable to analyze file: xxx INFO: Final Memory: 223M/750M INFO: ------------------------------------------------------------------------ at com.lintyservices.sonar.plugins.verilog.VerilogAnalyzerSensor.analyzeFile(VerilogAnalyzerSensor.java:160) at com.lintyservices.sonar.plugins.verilog.VerilogAnalyzerSensor.execute(VerilogAnalyzerSensor.java:111) ... Caused by: org.sonar.sslr.grammar.GrammarException: The regular expression 'xxx' has led to a stack overflow error. This error is certainly due to an inefficient use of alternations. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507 at org.sonar.sslr.internal.vm.PatternExpression.execute(PatternExpression.java:48) at org.sonar.sslr.internal.vm.Machine.execute(Machine.java:162) Caused by: java.lang.StackOverflowError at java.base/java.util.regex.Pattern$Branch.match(Unknown Source) at java.base/java.util.regex.Pattern$GroupHead.match(Unknown Source) ``` You need to increase the JVM stack size by setting the Xss variable to a higher value: ```bash # Add the following environment variable to the Docker container # Feel free to increase up to 100m. If you need to go higher, please report the issue to support@linty-service.com -e SONAR_SCANNER_OPTS=-Xss10m ``` #### java.lang.OutOfMemoryError: Java heap space If you face the following issue: ```bash ERROR: Error during SonarScanner execution java.lang.OutOfMemoryError: Java heap space ``` You need to increase the JVM heap space size by setting the Xmx variable to a higher value: ```bash # Add the following environment variable to the Docker container # Feel free to increase up to 4096m. If you need to go higher, please report the issue to support@linty-service.com -e SONAR_SCANNER_OPTS=-Xmx2048m ``` #### Insufficient privileges If you face the following issue, make sure that you [generated a token with proper User Token type](configure.md#generate-token-for-linty-scanner-user). ```bash org.sonarqube.ws.client.HttpException: Error 403 on https://xxx&metricKeys=ncloc_language_distribution : {"errors":[{"msg":"Insufficient privileges"}]} ``` #### sonar.hdl.topModule property is not set If you face the following issue, see [Top-level Module/Entity](top_level_module). ```bash ERROR: Error during SonarScanner execution ... Caused by: java.lang.IllegalStateException: [BUGFINDER] sonar.hdl.topModule property is not set ``` #### java.nio.file.AccessDeniedException: /opt/sonar-scanner/.sonar/cache/_tmp If you face the following issue, it means that you haven't created the cache directory before running the scan (`-v "/>:/opt/sonar-scanner/.sonar/cache"`). ```bash ERROR: Error during SonarScanner execution java.lang.IllegalStateException: Unable to create temp dir/opt/sonar-scanner/.sonar/cache/_tmp ... Caused by: java.nio.file.AccessDeniedException: /opt/sonar-scanner/.sonar/cache/_tmp ... ``` To fix this issue, remove the cache directory that Docker tried to create (but with wrong access rights), manually recreate the cache directory and re-run a scan. ### Docker Image Content * [SonarScanner](https://docs.sonarqube.org/latest/analyzing-source-code/scanners/sonarscanner/) * [Tabby CAD Linty Services Edition](https://www.yosyshq.com/tabby-cad-datasheet) with Linty Yosys Plugin * JDK 17