-
Notifications
You must be signed in to change notification settings - Fork 1.5k
fix(sonarqube): bypass 10K result cap by fetching issues per-rule - #448
fix(sonarqube): bypass 10K result cap by fetching issues per-rule #448TheAuditorTool wants to merge 1 commit into
Conversation
6286d30 to
698ae83
Compare
Closes OWASP-Benchmark#33 The issues/search API enforces p*ps <= 10000. With PAGE_SIZE=500, page 21 returns HTTP 400. Fix: iterate per-rule instead of passing all ~600 rules in one query. Each single-rule query stays well under 10K. Also fixes off-by-one in page count (ceiling division) and adds HTTP status checking before reading response body.
698ae83 to
adef7bc
Compare
davewichers
commented
Apr 14, 2026
@darkspirit510 - Another SonarQube related PR for you to review.
darkspirit510
commented
Aug 7, 2026
Sorry for the late reply!
Sonar-scanner is having some issues. This happens both on main and this PR, so it's not your fault. Could you still try to fix it or should I create another PR? (ignore the warning)
1:08:44.619 WARN Use of 'sonar.login' property has been deprecated in favor of 'sonar.token' (or the env variable alternative 'SONAR_TOKEN'). Please use the latter when passing a token.
21:08:44.621 INFO JRE provisioning: os[linux], arch[x86_64]
21:08:48.442 INFO EXECUTION FAILURE
21:08:48.443 INFO Total time: 6.093s
21:08:48.443 ERROR Error during SonarScanner CLI execution
java.lang.IllegalStateException: Project home must be an existing directory: /root/Develop/BenchmarkJava
at org.sonarsource.scanner.lib.internal.facade.Dirs.init(Dirs.java:40)
at org.sonarsource.scanner.lib.internal.facade.AbstractScannerEngineFacade.initAnalysisProperties(AbstractScannerEngineFacade.java:80)
at org.sonarsource.scanner.lib.internal.facade.AbstractScannerEngineFacade.analyze(AbstractScannerEngineFacade.java:63)
at org.sonarsource.scanner.cli.Main.analyze(Main.java:79)
at org.sonarsource.scanner.cli.Main.main(Main.java:64)
davewichers
commented
Aug 8, 2026
@TheAuditorTool - @darkspirit510 left you a comment on this PR.
I have notifications. I see everything @davewichers
@darkspirit510
This is my current life... I have 3 maintainers waiting for me to help them with various things.
I deleted my entire 322+ files and 100k loc rules/sast system, just days before the first public launch...
Just couldnt live with 5 generations of it... I estimated 2-3 weeks. I'm now at 2.5 with at least 2 weeks left.
Then i have a backlog of 3 other projects that isnt even my apps, 1 of which my app depends on for ip protection.
I also code 5 apps total. So if this has anything else then "Do it whenever you have time, if thats in 3 weeks or 3 months" priority?
I would suggest open a new PR yourself, Sascha.
Fun stats.... Or nightmare fuel, you decide....
14 Days on java-support . 293 commits. Your gut said 200-225 and undershot it by a third. The extra four days were the busiest stretch of the whole window.
1,271 files touched. 119,230 lines added, 190,313 deleted. Net: −71,083.
Two weeks of sustained work and the codebase is 71 thousand lines smaller. This is a demolition sprint, not a build sprint.
The daily curve
Jul 26 (Sun) 37 ████████████████████████████████████ +8,719 -7,011
Jul 27 (Mon) 22 ██████████████████████ +8,675 -4,230
Jul 28 (Tue) 27 ███████████████████████████ +14,989 -102,358 <- THE PURGE
Jul 29 (Wed) 32 ████████████████████████████████ +15,433 -4,154
Jul 30 (Thu) 3 ███ +679 -689 <- credits dying
Jul 31 (Fri) 7 ███████ +3,668 -680
Aug 01 (Sat) 9 █████████ +3,882 -1,657
Aug 02 (Sun) 16 ████████████████ +11,294 -6,071
Aug 03 (Mon) 48 ████████████████████████████████████████████████ +15,782 -7,224
Aug 04 (Tue) 0 --- <- credits gone
Aug 05 (Wed) 8 ████████ +4,328 -1,585
Aug 06 (Thu) 11 ███████████ +2,924 -14,797
Aug 07 (Fri) 8 ████████ +1,916 -1,712
Aug 08 (Sat) 47 ███████████████████████████████████████████████ +15,143 -26,065
Aug 09 (Sun) 21 █████████████████████ +13,200 -12,190
The Aug 4 hole has a twin. July 30 dropped to 3 commits and a 34-hour silence, then July 31 came back for exactly 6 commits in a 46-minute window at noon before going quiet again. The rate-limit wall shows up in the data as a two-humped crater: throttled July 30-31, recovered, then hit the ceiling completely on Aug 4.
The gap analysis makes it explicit:
25.8 h silence broken 08-03 23:08
21.2 h silence broken 08-07 00:08
18.5 h silence broken 08-05 01:07
15.5 h 13.7 h 11.5 h 11.1 h ...
Six separate silences over 11 hours in two weeks. The pattern of "long dead gap → immediate 40-commit day" is the signature of waiting on the meter and then spending it all at once.
Six breaking changes, every one a deletion
Jul 28 refactor(rules)! delete the legacy rules system (322 files)
Aug 05 refactor(taint)! rules alone assigns a CWE; producers emit facts
Aug 05 refactor(taint)! the grammar vocabulary and producer patterns leave taint/patterns
Aug 06 refactor(taint)! one deterministic sanitizer matcher, keyed on the declared grammar
Aug 06 refactor(graph)! delete the Java CST call-graph fallback
Aug 06 refactor(taint)! delete pipeline step 10
Four of six are taint. Aug 5-6 was a 48-hour window where you rebuilt that subsystem's contract three times.
The single largest commit in the window
94,013 lines | 5fed45e1 | Jul 28
refactor(rules)!: delete the legacy rules system (322 files)
The nocturnal signature holds, and sharpens
00:00 █████████████████████████████████████ 37 <- peak
01:00 ███████████████████████████ 27
02:00 ████████████████ 16
03:00 ███████ 7
04:00 ██████████████████ 18
05:00 ███ 3
...
11:00 █ 1 <- trough
...
21:00 ████████████████████████ 24
22:00 ██████████████████████████ 26
23:00 █████████████████████████████ 29
119 of 293 commits (41%) between midnight and 5am. The top four hours of your entire day are 00:00, 23:00, 01:00, 22:00 — in that order. 11am remains a single commit across two weeks.
187 of 293 (64%) landed within 15 minutes of the previous one.
darkspirit510
commented
Aug 24, 2026
@TheAuditorTool ever heard of this "vacation" everybody is talking about 😉
Just a minor request - can you merge main into this branch? I fixed the script, now I'd like to review this PR.
Closes #33
Refs #187
Summary
The SonarQube
/api/issues/searchendpoint enforces a hard server-side limit:p * ps <= 10000. WithPAGE_SIZE = 500, page 21 requests offset 10,500 andreceives HTTP 400. For instances reporting >10K vulnerabilities, results are
either silently truncated or the script crashes.
This was reported in #33 (March 2017) and deferred during the #187 cleanup.
The original reporter's suggestion -- filter by individual rules to keep each
query under the cap -- is exactly what this PR implements.
Problem Chain
&rules=squid:XXXper-rule.32933c4e6addedSonarReport.javawith native Java pagination. Passes ALL rules in one&rules=query -- still hits 10K cap for large result sets.dc9abba63fixed hostname.283e0e61fapplied Spotless formatting.What Changed
Single file changed:
src/main/java/org/owasp/benchmark/report/sonarqube/SonarReport.java1. Per-rule issue fetching (
main())Before: All ~600 Java rules are comma-joined into a single
&rules=queryparameter. If the aggregate result exceeds 10K issues, the API returns HTTP 400
or silently truncates.
After: Each rule is queried individually. A single rule produces far fewer
issues (typically 0-200 for Benchmark's 2,740 test cases), staying well under
the 10K cap.
This also fixes:
&&in the URL (&&rules=->&rules=)Why no duplicates: Each SonarQube issue belongs to exactly one rule.
Per-rule iteration produces disjoint result sets.
Performance: ~600 rules x 1 lightweight API call each. Most rules return 0
results (1 page). Total overhead: 1-5 minutes. The scan itself takes >= 1 hour.
2. Off-by-one in page count (
forAllPagesAt())Before:
(total / PAGE_SIZE) + 1-- always adds an extra page. When totalis an exact multiple of PAGE_SIZE (e.g., 500 issues), fires one unnecessary
empty-page request. At exactly 10K results, this triggers a forbidden page 21.
After:
(total + PAGE_SIZE - 1) / PAGE_SIZE-- standard ceiling division.3. HTTP error handling (
apiCall())Before:
getInputStream()on a non-200 response throws a genericIOExceptionwith "Server returned HTTP response code: 400 for URL: ...".For some error codes, it may silently read an error body that breaks Jackson
deserialization downstream.
After:
getResponseCode()is checked before reading the body. Non-200throws
IOException("SonarQube API returned HTTP " + status + " for " + apiPath)with clear context.
What Was NOT Changed
testcode/(2,740 files)SonarQubeResult.javaKeepAsJsonDeserializer.javarunSonarQube.shpom.xmlsetDoOutput(true)inapiCall()Known Limitations (future work)
hotspots/searchhas the same 10K cap but does not support per-rulefiltering. Benchmark's 2,740 test cases are unlikely to produce 10K+
hotspots, but an Enterprise instance could. Addressing this requires a
different partitioning strategy (by file or security category).
rules/searchalso paginates with the same mechanism. Default SonarQubehas ~3,000 rules total, well under 10K. Only relevant for instances with
10K+ custom rules.
Test Plan
scripts/runSonarQube.shon a machine with Dockerresults/Benchmark_*-sonarqube-v*.jsoncontains bothissuesandhotspotsarrayssonarqube-benchmarkcontainer after script completes