|
ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
|
This repository is analyzed by SonarCloud. Because the codebase is C/C++, the analysis is CI-based (a GitHub Actions workflow), not SonarCloud's "Automatic
Analysis": automatic analysis cannot analyze C/C++ because it has no build to observe. The C/C++ analyzer needs a compilation database (compile_commands.json) describing how each source file is compiled.
SONAR_TOKEN** (Settings -> Secrets and variables -> Actions). The SonarCloud scan (part of the Test & Analyze workflow) is a no-op until this secret exists.sonar.projectKey and sonar.organization in sonar-project.properties match your SonarCloud project (SonarCloud -> Information). The defaults follow SonarCloud's GitHub-import convention (<owner>_<repo> and <owner>).No single build enables all ~111 PC_ENABLE_* features, so a feature-gated source file is only compiled in the env whose flag turns it on. To give Sonar a command for every file, ci_tooling/sonar/gen_compiledb.sh runs pio run -t compiledb for each native env, and ci_tooling/sonar/merge_compiledb.py merges the per-env fragments into one compile_commands.json (first env to compile a file wins). The CI workflow runs this so the database's absolute directory matches the runner's checkout; compile_commands.json itself is git-ignored.
Run it locally the same way (with PlatformIO on PATH):
Cost note: merging every env means one
compiledbbuild per native env, which is the slow part of the CI job (the PlatformIO cache mitigates re-runs). If that is too slow, a single all-features build is a faster, slightly less complete alternative.
SonarCloud does not run the tests; it only displays coverage from a report you import, so without one it shows 0%. ci_tooling/coverage/gen_coverage.sh builds + runs the native Unity test envs with gcov instrumentation (-fprofile-arcs -ftest-coverage -lgcov, into a dedicated .pio_cov build dir).
It emits one gcovr report per env and then ci_tooling/coverage/merge_coverage.py unions them into coverage.xml (SonarQube generic-coverage format, src/ only). The per-env split is required: gcov cannot merge the same source compiled with different -D flags across envs in a single pass - it raises a worker exception - so each env is gcovr'd on its own build dir and the reports are merged afterwards (a line is covered if covered in any env). The scan imports the result via sonar.coverageReportPaths=coverage.xml.
coverage.xml, coverage_reports/, and .pio_cov are git-ignored; the CI job regenerates them. Run locally with bash ci_tooling/coverage/gen_coverage.sh (or pass a subset of env names as args). The ThreadSanitizer env is excluded (tsan + gcov do not mix), and the step roughly doubles the CI job time (it runs every test env on top of the compile-DB build).
SonarCloud reports ~68% line coverage. That is lower than gcovr's ~84% over the natively-built files because SonarCloud also counts the ESP32/platform-only files the native tests cannot build (TLS, mDNS, OTA, the lwIP shims, the route registrars) as uncovered; an ESP32 cross-toolchain coverage fragment would lift it.
The merged database covers every source file the host (native) toolchain compiles (115 of the library's .cpp files as of this writing). The handful it does not cover are ESP32/platform-only and never built natively: the TLS engine (tls.cpp), the lwIP datalink/network shims, the ESP-IDF mDNS/OTA services, the TCP client, and the dashboard/gpio/partition route registrars. To analyze those too, add an ESP32 compiledb (cross-toolchain) fragment to the merge; it needs the espressif32 toolchain in the CI job.
The first scan reported all bugs and vulnerabilities (now fixed - see BUGS.md) plus ~2169 "code smells". The large majority of those smells come from a handful of rules that contradict this library's deliberate, documented design, so they are noise here, not defects. Tune them out in a custom SonarCloud quality profile (or bulk "Won't Fix") rather than churning the code - changing them would break the design guarantees:
| Rule | Name | Why it does not apply here |
|---|---|---|
cpp:S5028 | Macros should not define constants | The whole compile-time feature/config system is #define (zero cost, #if-gated). |
cpp:S5945 | C-style array should not be used | Zero-heap: every buffer is a fixed C array; no std::array/STL. |
cpp:S5421 | Non-const global variables | Static pools (conn_pool, ...) are the static-allocation model. |
cpp:S5205 | Function pointers as parameters | Callbacks are raw function pointers on purpose (std::function heaps). |
cpp:S3642 | Scoped enumerations should be used | Plain enums for C-ABI / terse embedded style. |
cpp:S5827/S5826 | "auto" should be used | The codebase prefers explicit types (see the coding-style guide). |
cpp:S1659 | One variable declaration per line | Stylistic; conflicts with the terse style. |
The remaining smells are worth a case-by-case look but are mostly by-design: cpp:S5813 (use strnlen) fires on strlen over internal NUL-terminated buffers (external input is already bounded by the parsers); cpp:S995 (const pointer params) is partly real const-correctness; cpp:S134/cpp:S3776 (deep nesting / cognitive complexity) flag the protocol-dispatch parsers, where a flat switch is the clearest structure. The lone blocker-level smell (cpp:S912, a side effect inside an &&) was fixed.
The free/public SonarCloud plan cannot assign a custom quality profile to the project, so the design-conflict rules cannot simply be disabled - each open issue is marked individually instead. ci_tooling/sonar/accept_style_conflicts.py automates that: it transitions the design-conflict style rules to Accepted (won't fix) and a few provable non-issues (e.g. strncpy that is always followed by an explicit NUL terminator, protocol field-annotation comments) to False Positive, each with a justification. Genuine reviewer signals - cpp:S134, cpp:S3776, cpp:S107 and cpp:S5813 - are left open on purpose. New code re-flags the same style rules, so re-run it after a scan:
Real BUG / VULNERABILITY findings are always fixed at source, never marked.