Coverage baseline - #94
Merged
Merged
Conversation
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 2, 2026 07:44
e28850b to
4c37898
Compare
insatomcat
added a commit
that referenced
this pull request
Aug 2, 2026
…alysis The project runs SonarCloud Automatic Analysis (autoscanEnabled=true, ciName=Autoscan): the SonarCloud GitHub App analyses every push server-side, with no scanner in the repository. That mode cannot work for what this branch is about, for two reasons. Automatic Analysis never runs the build or the tests, so it cannot import a coverage report. SonarCloud has therefore never had coverage data for this project: the `coverage` metric is absent on main and `new_lines_to_cover` is 0 on pull requests. The coverage.xml produced by CI has nowhere to go. It also has no git history to blame lines with, so on a pull request every line of a touched file counts as new code. On PR #94 that is visible on .github/workflows/ci.yml line 54: the line is identical to main, at the same line number, and SonarCloud dates the issue on it 2026-02-19, yet it lands in the new-code period and fails the new_security_rating gate. main itself is green with the same four findings. Run the scanner from the test job instead, after the tests, with fetch-depth: 0 so blame works, and declare the coverage report path in sonar-project.properties. Scope stays the whole repository as it was under Automatic Analysis, so the workflow, Dockerfile and XML analysers keep reporting. Requires two manual steps before this can work: turn Automatic Analysis off in the SonarCloud project settings, and add the SONAR_TOKEN repository secret. SonarCloud rejects a CI analysis while Automatic Analysis is enabled, so the order matters.
insatomcat
added a commit
that referenced
this pull request
Aug 2, 2026
…alysis The project runs SonarCloud Automatic Analysis (autoscanEnabled=true, ciName=Autoscan): the SonarCloud GitHub App analyses every push server-side, with no scanner in the repository. That mode cannot work for what this branch is about, for two reasons. Automatic Analysis never runs the build or the tests, so it cannot import a coverage report. SonarCloud has therefore never had coverage data for this project: the `coverage` metric is absent on main and `new_lines_to_cover` is 0 on pull requests. The coverage.xml produced by CI has nowhere to go. It also has no git history to blame lines with, so on a pull request every line of a touched file counts as new code. On PR #94 that is visible on .github/workflows/ci.yml line 54: the line is identical to main, at the same line number, and SonarCloud dates the issue on it 2026-02-19, yet it lands in the new-code period and fails the new_security_rating gate. main itself is green with the same four findings. Run the scanner from the test job instead, after the tests, with fetch-depth: 0 so blame works, and declare the coverage report path in sonar-project.properties. Scope stays the whole repository as it was under Automatic Analysis, so the workflow, Dockerfile and XML analysers keep reporting. Requires two manual steps before this can work: turn Automatic Analysis off in the SonarCloud project settings, and add the SONAR_TOKEN repository secret. SonarCloud rejects a CI analysis while Automatic Analysis is enabled, so the order matters. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 2, 2026 08:22
3262577 to
c8c4b54
Compare
insatomcat
added a commit
that referenced
this pull request
Aug 2, 2026
…alysis The project runs SonarCloud Automatic Analysis (autoscanEnabled=true, ciName=Autoscan): the SonarCloud GitHub App analyses every push server-side, with no scanner in the repository. That mode cannot work for what this branch is about, for two reasons. Automatic Analysis never runs the build or the tests, so it cannot import a coverage report. SonarCloud has therefore never had coverage data for this project: the `coverage` metric is absent on main and `new_lines_to_cover` is 0 on pull requests. The coverage.xml produced by CI has nowhere to go. It also has no git history to blame lines with, so on a pull request every line of a touched file counts as new code. On PR #94 that is visible on .github/workflows/ci.yml line 54: the line is identical to main, at the same line number, and SonarCloud dates the issue on it 2026-02-19, yet it lands in the new-code period and fails the new_security_rating gate. main itself is green with the same four findings. Run the scanner from the test job instead, after the tests, with fetch-depth: 0 so blame works, and declare the coverage report path in sonar-project.properties. Scope stays the whole repository as it was under Automatic Analysis, so the workflow, Dockerfile and XML analysers keep reporting. Requires two manual steps before this can work: turn Automatic Analysis off in the SonarCloud project settings, and add the SONAR_TOKEN repository secret. SonarCloud rejects a CI analysis while Automatic Analysis is enabled, so the order matters. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 2, 2026 08:24
c8c4b54 to
d4bd3a0
Compare
insatomcat
added a commit
that referenced
this pull request
Aug 2, 2026
…alysis The project runs SonarCloud Automatic Analysis (autoscanEnabled=true, ciName=Autoscan): the SonarCloud GitHub App analyses every push server-side, with no scanner in the repository. That mode cannot work for what this branch is about, for two reasons. Automatic Analysis never runs the build or the tests, so it cannot import a coverage report. SonarCloud has therefore never had coverage data for this project: the `coverage` metric is absent on main and `new_lines_to_cover` is 0 on pull requests. The coverage.xml produced by CI has nowhere to go. It also has no git history to blame lines with, so on a pull request every line of a touched file counts as new code. On PR #94 that is visible on .github/workflows/ci.yml line 54: the line is identical to main, at the same line number, and SonarCloud dates the issue on it 2026-02-19, yet it lands in the new-code period and fails the new_security_rating gate. main itself is green with the same four findings. Run the scanner from the test job instead, after the tests, with fetch-depth: 0 so blame works, and declare the coverage report path in sonar-project.properties. Scope stays the whole repository as it was under Automatic Analysis, so the workflow, Dockerfile and XML analysers keep reporting. Requires two manual steps before this can work: turn Automatic Analysis off in the SonarCloud project settings, and add the SONAR_TOKEN repository secret. SonarCloud rejects a CI analysis while Automatic Analysis is enabled, so the order matters. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 2, 2026 18:43
d4bd3a0 to
ce42ddf
Compare
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 2, 2026 18:49
ce42ddf to
2313d04
Compare
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 4, 2026 07:14
e982516 to
6138c48
Compare
insatomcat
marked this pull request as ready for review
August 4, 2026 07:18
vm_manager selects its backend when it is first imported: if `rados` and `rbd` are importable it exposes the cluster API, otherwise the libvirt-only one. Those bindings ship with Ceph and are not installable from PyPI, so on the CI runner `cluster_mode` is False. The consequence was that tests/test_vm_manager_cmd.py, whose docstring says it has no cluster dependencies, was skipped in its entirety by its own `skipif(not vm_manager.cluster_mode)` guard. The only pure unit tests in the repository never actually ran. Register stub `rados` and `rbd` modules from tests/conftest.py, before vm_manager is imported, when the real bindings are absent. The stubs only satisfy the import: instantiating one raises, so a test that reaches real Ceph code fails loudly rather than passing against a fake. On a machine with Ceph the genuine bindings are found and nothing is stubbed. CI now collects 36 tests instead of 32 plus 4 skipped, and cluster-side code that needs no cluster (argparse, XML building, crm command construction) becomes reachable by future unit tests. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 4, 2026 07:27
6138c48 to
fc80aca
Compare
Cover the argparse layer and the main() dispatch table with every
vm_manager entry point replaced by a recorder, so nothing here needs
libvirt, Ceph or Pacemaker: the ParseMetaData action, the registered
subcommands and their required arguments, and the function plus
arguments main() forwards each command to.
Statement coverage of vm_manager_cmd.py goes from 39% to 92%. What is
left uncovered is the standalone-mode half of get_parser(), which cannot
be reached while the tests run in cluster mode.
Three tests are marked xfail(strict) because they document two real
bugs found while writing them:
- `create --disable` and `clone --disable` do not disable anything.
main() only assigns args.enable under `if "enable" in args`, but
`enable` is never an argparse dest for those subcommands, so the key
never reaches the backend, and _configure_vm() treats a missing
'enable' key as True.
- `create --enable-live-migration` is a no-op. main() guards the
rename with `if "live_migration" in args`, and `live_migration` is
likewise never a dest, so _configure_vm() never writes the
_live_migration metadata.
add-to-cluster assigns both unconditionally and behaves correctly; the
tests covering it are the reference for what create and clone should do.
Coverage confirms the diagnosis: lines 542, 547 and 550 of
vm_manager_cmd.py are unreachable.
The markers are strict, so whoever fixes the guards will get an XPASS
failure telling them to drop the marker.
Signed-off-by: Florent Carli <florent.carli@rte-france.com>
The OpenSSF gold criteria test_statement_coverage90 and test_branch_coverage80 both require a measured number, and nothing in this repository measured one: no pytest-cov, no coverage configuration, no CI step. Add pytest-cov and coverage[toml] to the `test` extra, enable branch coverage over the vm_manager package (excluding the hand-driven integration scripts under vm_manager/helpers/tests/), and have CI print a summary table in the job summary and publish coverage.xml plus the HTML report as an artifact. No exclusions and no fail_under for now: the point of this change is to get an honest baseline before deciding where to set thresholds. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
The two pip install steps resolved their dependencies freely and accepted source distributions. A run could therefore install different versions than the previous one, and any dependency could execute a setup script at install time. SonarCloud reports both, as githubactions:S8544 and githubactions:S8541. Pin the versions through a pip constraints file rather than by narrowing the ranges declared in pyproject.toml: the package keeps its permissive ranges for downstream users, only CI is nailed down. The pinned versions are the ones the workflow already resolved, so nothing changes but the drift. Restrict both steps to wheels. libvirt-python cannot follow, it publishes no wheel on PyPI and compiles against the system libvirt headers, which is what the libvirt-dev and pkg-config packages installed above are for. Excluding it by name keeps source builds to that single reviewed package rather than reopening them for the whole dependency graph. The docs step becomes editable as well. It used to reinstall the package as a copy over the editable install, which was pointless since the tests had already put it in place. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
insatomcat
force-pushed
the
coverage-baseline
branch
from
August 4, 2026 07:30
fc80aca to
9a7461e
Compare
…alysis The project ran SonarCloud Automatic Analysis (ciName=Autoscan): the SonarCloud GitHub App analysed every push server-side, with no scanner in the repository. That mode cannot serve what this branch is about, for two reasons. Automatic Analysis never runs the build or the tests, so it cannot import a coverage report. SonarCloud consequently had no coverage data for this project at all: the `coverage` metric is absent from the project measures and `new_lines_to_cover` is 0 on pull requests. The coverage.xml the previous commit produces would have nowhere to go. It also has no git history to blame lines with, so on a pull request every line of a touched file counts as new code. That was visible on this branch before it was fixed: an issue on a line of .github/workflows/ci.yml identical to main, at the same line number, dated 2026-02-19 by SonarCloud itself, still landed in the new-code period and failed the new_security_rating gate, while main stayed green with the same finding. Run the scanner from the test job instead, after the tests, with fetch-depth: 0 so blame works, and declare the coverage report path in sonar-project.properties. Scope stays the whole repository as it was under Automatic Analysis, so the workflow, Dockerfile and XML analysers keep reporting. Automatic Analysis has been turned off in the project settings and the SONAR_TOKEN repository secret is in place, which this step needs. It is skipped when the secret is unavailable, as happens for pull requests opened from a fork; those keep the rest of the job. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
|
eroussy
approved these changes
Aug 6, 2026
insatomcat
added a commit
that referenced
this pull request
Aug 6, 2026
The New Code definition is "previous version" and no analysis ever ran with one, so the period falls back to the first analysis ever: 3562 new lines for 3334 lines of code, the whole code base. That is what turned the main gate red on new_coverage and new_security_rating as soon as #94 published coverage. Pull requests were never affected, their gate is computed on their own diff. Pass the version from pyproject.toml, which stays the single source of truth, so each release gives the period a real boundary. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
insatomcat
added a commit
that referenced
this pull request
Aug 7, 2026
The New Code definition is "previous version" and no analysis ever ran with one, so the period falls back to the first analysis ever: 3562 new lines for 3334 lines of code, the whole code base. That is what turned the main gate red on new_coverage and new_security_rating as soon as #94 published coverage. Pull requests were never affected, their gate is computed on their own diff. Pass the version from pyproject.toml, which stays the single source of truth, so each release gives the period a real boundary. Signed-off-by: Florent Carli <florent.carli@rte-france.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Establishes a measured coverage baseline for vm_manager, as a first step
towards the OpenSSF Best Practices gold criteria
test_statement_coverage90and
test_branch_coverage80.What it contains
vm_manager_cmdCLI (55 tests). They monkeypatchthe public API, so they check argument parsing and dispatch, not the
backends.
vm_manager_cmd.pygoes to 92%.tests/conftest.pyinstallsthe stubs from
tests/ceph_stubs.pybefore importing vm_manager, becausethe backend is chosen at import time in
__init__.py. Without themcluster_modeis False on any machine without Ceph and every cluster-sidetest is skipped, including those that need no cluster at all. The stubs
raise on use, so a test that reaches real Ceph code fails loudly instead of
passing quietly.
figures are readable and linkable without any third party service.
which is what finally lets the coverage report reach SonarCloud. Also
detailed below.
The baseline
26% is low and the reason is structural, not a gap in the suite. CI runs 87
of the 178 test functions. The 91 it ignores are
test_vm_manager_cluster.pyand
test_vm_manager_cmd_cluster.py, which need a real Ceph and Pacemakercluster. Those are exactly the tests covering
vm_manager_cluster.py,rbd_manager.pyandpacemaker.py, which together are 1115 of the 1529statements. Closing the gap means unit tests with the bindings and the
crmCLI mocked, which is the next step, not this one.
There is deliberately no
fail_underyet. Setting a threshold beforehaving an honest baseline would only encode the current state as a target.
SonarCloud will show 21.2%, not 26%, and both are correct. The two
figures measure slightly different things, so it is worth writing the
reconciliation down once:
pyproject.tomlomitsvm_manager/helpers/tests/*from the measurement,the hand-run integration scripts. That is 522 statements. 1529 + 522 =
2051, against the 2042 coverable lines SonarCloud reports: same code, plus
those scripts, counted as fully uncovered. They are shipped in the
installed package, so SonarCloud is right to count them, and the scope is
deliberately left alone rather than tuned to make the two numbers agree.
reports them apart: 22.4% line, 16.6% branch, 21.2% overall.
The CI hardening commit
It exists because SonarCloud reported four findings on the two
pip installlines, under two rules, and both are legitimate.
githubactions:S8544, dependencies without locked versions. Fixed withrequirements-ci.txtused as a pip constraints file. The permissiveranges in
pyproject.tomlare untouched, so nothing changes for anyoneinstalling the package. Only CI is pinned.
githubactions:S8541, source distributions may run setup scripts atinstall time. Fixed with
--only-binary :all:, withlibvirt-pythonexcluded by name: it publishes no wheel on PyPI and compiles against the
system libvirt headers, which is what the
libvirt-devandpkg-configapt packages in the workflow are for. Naming it keeps source builds to that
single reviewed package rather than reopening them for the whole dependency
graph.
The install is also editable. Coverage instruments the package in the
checkout, so the tests must import it from there. A regular install copies it
to site-packages, the tests import that copy, and coverage reports 0% on
every module while the suite passes.
SonarCloud analysed from the workflow
The project ran SonarCloud Automatic Analysis: the GitHub App analysed
every push server-side, with no scanner in the repository. That mode cannot
serve this change, for two reasons.
report. SonarCloud has had no coverage data at all for this project:
the
coveragemetric is simply absent from the project measures, andnew_lines_to_coveris 0 on pull requests. Producing acoverage.xmlinCI is useless as long as nothing can consume it.
of a touched file counts as new code. That is why this branch first went
red on a line of
ci.ymlidentical tomain, at the same line number,dated 2026-02-19 by SonarCloud itself, while
mainstayed green on thesame finding.
So the scanner now runs from the
testjob, after the tests, withfetch-depth: 0so blame works, andsonar-project.propertiesdeclares thecoverage report path. Scope stays the whole repository as it was under
Automatic Analysis, so the workflow, Dockerfile and XML analysers keep
reporting. The step is skipped when
SONAR_TOKENis absent, which is thecase for pull requests from forks: those keep the rest of the job.
Automatic Analysis has been turned off in the project settings and the
SONAR_TOKENrepository secret is in place, both prerequisites for theabove. The trade-off is worth stating: pull requests from forks are no
longer analysed at all, where Automatic Analysis did analyse them. In
exchange the project gets coverage and correct new-code detection, neither
of which Automatic Analysis can ever provide.
This already works on this pull request. The analysis run from the workflow
reports
coverage 21.2,line_coverage 22.4,branch_coverage 16.6over2042 coverable lines, and the quality gate is green. Before it, the
coveragemetric did not exist on the project at all.Known issues left open on purpose
Three tests are marked
xfail(strict=True)because they document two realCLI bugs rather than hide them:
create --disableandclone --disabledisable nothing.main()onlyassigns
args.enableunderif "enable" in args, butenableis never anargparse dest for those subcommands, so the key never reaches the backend
and
_configure_vm()treats a missingenableas True.create --enable-live-migrationis a no-op, same pattern withif "live_migration" in args.add-to-clusterassigns both unconditionally and is the correct reference.Fixing them changes CLI behaviour, so it belongs in its own change.