Gate CI builds with Qodana severity thresholds and Docker
Run Qodana from a pinned Docker image in CI with --severity thresholds and qodana.yml to enforce consistent static-analysis gates.
12 Sept 2026, 22:01 UTC

Problem: inconsistent static-analysis gates across runners
Teams often run Qodana locally with one configuration and then discover different findings in CI. Without a pinned container image, each runner may pull a different Qodana version, and without a severity threshold, the build can fail on low-priority warnings or pass despite serious issues.
Useful takeaway
Run Qodana from a pinned Docker image in CI, mount the repository into /src, and use the --severity flag so the build fails only on findings at or above the level you choose. Keep language plugins and custom rules in qodana.yml so the same configuration runs everywhere.
How the Docker-based gate works
Qodana ships as a Docker image containing the analysis engine and language-specific plugins. When the container starts, it reads qodana.yml from the mounted workspace, analyzes the source, and exits with a non-zero status if issues meet or exceed the severity threshold. Results can be emitted as SARIF for upload to GitHub Code Scanning or another compatible viewer.
Terms: severity threshold is the minimum issue severity that causes a non-zero exit code. pinned image means referencing a specific tag or digest rather than :latest, so the CI environment does not change when the upstream image is updated.
Worked configuration
Create a qodana.yml in the repository root. The example below is representative; confirm exact keys against the documentation for your pinned Qodana version.
linter:
python:
enabled: true
profile:
name: bandit
Run the container from the CI job shell or a local terminal with Docker access. Replace <image-tag> with a specific version tag or digest.
docker run --rm \
-v "$(pwd):/src" \
-v qodana-cache:/root/.cache/Qodana \
qodana/qodana: \
--severity ERROR
Where to run: any CI runner with Docker, or locally for reproduction. Required permissions: the executing user must be able to run Docker, typically through the docker group or sudo. Placeholders: <image-tag> is the Qodana image version; $(pwd) resolves to the repository root on Linux and macOS runners.
Expected checks: if no findings at ERROR severity or higher exist, the container exits with code 0. If a high-severity issue is found, it exits non-zero and the CI job fails. Check the CI log for a line referencing the severity threshold to confirm the flag was applied.
Risks: using :latest can introduce nondeterministic behavior when the image is updated. Large repositories may exceed the default analysis timeout; tune it with --timeout if the job is killed before completion.
GitHub Actions example
jobs:
qodana:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Qodana severity gate
run: |
docker run --rm \
-v "${{ github.workspace }}:/src" \
-v qodana-cache:/root/.cache/Qodana \
qodana/qodana: \
--severity ERROR
Cache volume reuse across jobs depends on your runner setup; on ephemeral GitHub-hosted runners, the named volume may not persist between workflow runs.
Limits and common mistakes
- Unpinned image tag:
qodana/qodana:latestmay pull a newer release with different default rules or CLI behavior. - Old releases: Qodana versions before 1.0 may not support
--severityand can misinterpret threshold values. - Timeout: large monorepos often need an explicit
--timeoutvalue because the default analysis window may be too short. - Wrong severity level:
ALLfails on minor style issues;ERRORmay skip actionable warnings. Choose based on your team's quality gate policy. - Missing SARIF upload: running Qodana produces findings, but they are not visible in pull requests unless you upload the SARIF artifact to GitHub Code Scanning or an equivalent tool.
Verify the result
- Run
docker run --rm qodana/qodana: --helpand confirm the CLI version and available flags. - Create a minimal repository with one harmless file, such as
print(1)in Python, run the command above, and confirm the build succeeds with zero findings. - Inspect the CI log for a severity-threshold message and check the exit code with
echo $?immediately after the container finishes. - If you enabled SARIF output, confirm the report file exists and can be opened by a SARIF viewer before uploading it to your code-scanning pipeline.
This operation is read-only with respect to your source code, so there is no database or artifact rollback. If you add the step to CI and it blocks merges, remove or adjust the --severity value in the workflow file and redeploy the pipeline.
Verification note: flag names, default timeouts, and qodana.yml schema vary by Qodana version. Confirm them against the documentation for the image tag you pin before merging the CI change.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.