ci: fail test jobs when no tests are registered - #112
Conversation
srpatcha
left a comment
There was a problem hiding this comment.
Review — eBoot#112 "ci: fail test jobs when no tests are registered"
head: 58a1792 author: dipanshurdev ci: fail (6 required checks red — inherited from master, not caused here)
Verdict: The change is correct and complete within the scope it declares, and the body's
claims hold up — I checked every ctest line in .github/workflows/ and all five edited
sites are preceded by a configure with -DEBLDR_BUILD_TESTS=ON, so the guard cannot
spuriously fail. The problem is the scope. The repository's security suite has the
identical defect and is not in .github/workflows/, so this PR walked past it. I
reproduced that one running: it collects zero tests and exits 0.
Findings
| # | Severity | File:line | Finding | Recommended fix |
|---|---|---|---|---|
| 1 | High | ci/security_test.sh:21-33 |
The security suite's unit-test step runs nothing and reports success. The script configures with -DEBLDR_BUILD_FUZZ=ON and never passes -DEBLDR_BUILD_TESTS=ON; CMakeLists.txt:23 defaults that option to OFF. Step 2 then runs ctest --output-on-failure --timeout 120 with no guard. I ran exactly that against a configure with those flags: No tests were found!!! / EXIT=0. The script is set -euo pipefail, so it prints "Running unit tests (ASAN+UBSAN)" and proceeds to the fuzz step as though the sanitizer run had passed. This is the precise failure .ai/security.md names — "a security suite that silently collected nothing is a failed check reported as green; always --no-tests=error" — and it is live, not hypothetical. |
Two lines: add -DEBLDR_BUILD_TESTS=ON to the cmake -B "${BUILD_DIR}" invocation at :21, and --no-tests=error to the ctest at :33. Same guard at ci/ci_security.yml:66. Worth pulling into this PR — it is the highest-value instance of the exact defect the PR is about. |
| 2 | Medium | ci/ci_security.yml:1-12 |
This workflow has never run. It is a GitHub Actions workflow living at ci/ci_security.yml, not under .github/workflows/, so Actions does not pick it up — nothing in the tree references it either (git grep ci_security matches only its own header comment). Its on: block compounds it: push: branches: [main, develop] and pull_request: branches: [main], while this repo's default branch is master. So even if it were moved, it would still not fire on PRs. Its ctest at :66 carries the same missing guard as finding 1. |
Decide and say which: move it to .github/workflows/security.yml and fix the branch filters to master, or delete it as dead configuration. Leaving a file that reads like security CI but executes nowhere is worse than not having it — it is the kind of thing a reader counts as coverage. |
| 3 | Medium | .github/workflows/weekly.yml:76-81 |
Valgrind results are discarded. The Memcheck job runs valgrind --error-exitcode=1 ... "$test" || true in a loop, so no memory error can ever fail the job — --error-exitcode=1 is inert next to || true. The loop itself has the same class of bug this PR set out to fix: for test in $(find build -name "test_*" -type f -executable) iterates zero times if the build layout changes, and the step still exits 0 having checked nothing. Per .ai/reviewer.md, a verification whose result is discarded is a finding regardless of the reason given. This PR edits weekly.yml and leaves it. |
Drop || true, and fail the step when the glob is empty: collect into an array, [ ${#tests[@]} -gt 0 ] || { echo "no test binaries found"; exit 1; }. Better still, use ctest -T memcheck so the existing valgrind_* targets in tests/CMakeLists.txt:226 are the single source of truth. |
| 4 | Medium | .github/workflows/build.yml:68-73, .github/workflows/ci.yml:183-187 |
Both "Static Analysis" checks are structurally incapable of failing, and both report pass in this PR's own check list. build.yml runs cppcheck ... --error-exitcode=1 core/ hal/ 2>&1 || true; ci.yml runs cppcheck with continue-on-error: true. In both cases --error-exitcode=1 is cancelled out. A green "Static Analysis" on this PR therefore carries no information, which matters because two of the six red checks are analysis-adjacent and a reviewer reading the list would reasonably assume the green ones mean something. |
Out of scope for this PR, but it belongs on the same list as findings 1-3: remove || true from build.yml:73 and continue-on-error: true from ci.yml:187, and land the resulting cppcheck failures as their own work. If the suppression is deliberate because the backlog is large, say so in the workflow with a comment and a tracking issue rather than leaving it silent. |
| 5 | Low | CONTRIBUTING.md:34,101,125, README.md:47,80, .github/PULL_REQUEST_TEMPLATE.md:31 |
Six documented ctest command lines still omit --no-tests=error. After this PR, CI and the documentation disagree about what "run the tests" means, and the PR template asks a contributor to tick "Unit tests pass" against the weaker command. Per the project's documentation rule, a change that makes existing docs wrong is not finished. |
Add the flag to all six. Mechanical, and it keeps the contributor's local command identical to the one CI runs. |
| 6 | Low | (whole PR) | The body's Verification says "The GitHub Actions workflows will provide CI validation for the changed commands." They have not and currently cannot: six required checks are red, and I confirmed locally that the host build fails on pre-existing core/sha512.c and core/ed25519_verify.c errors present on clean origin/master. Every edited ctest step sits behind a cmake --build that never completes, so not one of the five changed lines has executed. |
No code change. Replace the future-tense sentence with the present-tense truth: the edits are unverified by CI, blocked behind #111 and #115. The distinction matters under §28's evidence policy. |
What the PR gets right
- All five
ctestinvocations under.github/workflows/are covered.git grep -n ctest
at this head returns seven lines; the other two areci.yml:66(already guarded) and
ci.yml:64(a comment). Nothing in.github/workflows/was missed. - The "confirmed all configure with
EBLDR_BUILD_TESTS=ON" claim is accurate. I checked
each:build.yml:27,nightly.yml:27,nightly.yml:120,release.yml:25,
weekly.yml:26. So the guard will not turn a legitimately-green job red. - No test was disabled, no assertion removed, no permission widened. The diff is four
files, five lines, all in the fail-closed direction.
Verification performed for this review
Detached scratch worktree under .ai/autoreview/state/verify/; the user's checkout was
not touched, nothing was pushed.
| Check | Result |
|---|---|
ctest --output-on-failure --timeout 120 against a tree configured the way ci/security_test.sh configures it |
Reproduced the defect — No tests were found!!!, EXIT=0 |
Same invocation with --no-tests=error appended |
No tests were found!!!, Errors while running CTest, EXIT=8 — the guard works as claimed |
grep -n "option(EBLDR_BUILD_TESTS" CMakeLists.txt |
CMakeLists.txt:23 — default OFF, confirming finding 1's premise |
Host build of eBoot from clean origin/master |
FAIL — core/sha512.c ×5, core/ed25519_verify.c:303; confirms the red checks are inherited |
| The five edited workflow steps | NOT RUN — unreachable behind the failing build |
Architecture conformance
Conforms. §21: eBoot is Tier 1 Foundation; CI configuration belongs in the owning repo.
No #include, link line, target_link_libraries entry or manifest dependency changes, so
§5.1's dependency direction is untouched. The change serves §28's status/evidence policy
directly — a test job that reports success while registering zero tests is the mechanism
by which "Implemented" gets claimed without evidence, and .ai/security.md's fail-closed
rule names --no-tests=error explicitly.
Proposed changes
Smallest sequence, in priority order:
1. In this PR, extend the same guard to the security runners:
ci/security_test.sh:21 add -DEBLDR_BUILD_TESTS=ON to the cmake configure
ci/security_test.sh:33 ctest --output-on-failure --timeout 120 --no-tests=error
ci/ci_security.yml:66 ctest --output-on-failure --timeout 120 --no-tests=error
2. Update the six documented command lines (CONTRIBUTING/README/PR template).
3. Correct the body's Verification section to present tense.
Separate PRs, not this one:
4. weekly.yml:80 drop `|| true`, fail on an empty test-binary list
5. build.yml:73 drop `|| true`; ci.yml:187 drop `continue-on-error: true`
6. ci/ci_security.yml — move under .github/workflows/ with master branch filters, or delete
Why no fix PR was opened
Finding 1 is High and the fix is three lines, which meets the bar for an autofix. I did not
open one: fix-verify.sh would have to run the repo's real checks inside the worktree, and
eBoot's master does not compile right now (verified above), so the build label would fail
and fix-submit.sh would correctly refuse the PR. This is worth revisiting once #115 lands.
Not checked
- I did not run
ci/security_test.shend to end. Finding 1 is proven for step 2
(unit tests under sanitizers) by reproducing thectestinvocation against an
equivalently-configured tree. Steps 3-4 (fuzz targets, Valgrind) were not executed —
clang, libFuzzer and valgrind availability here is unverified, and whether those steps
have their own fail-open defects is unknown. - Whether any open eBoot PR other than the five in this run's manifest already fixes
ci/security_test.shor movesci/ci_security.yml. I compared against this run's
manifest only, so finding 1 could duplicate an existing PR I have not seen. - I did not read the six red job logs. Their failure is attributed to the inherited build
break because I reproduced that break locally on cleanmaster, not because I confirmed
each job's failing step. - Cross-compile and fuzz-harness behaviour under the new guard: not exercised, since those
jobs do not reachctest.
Automated architecture review of 58a17922d945 — scheduled, model claude-opus-5, checked against the EmbeddedOS Master Design v2.0. Advisory only: this reviewer never approves, requests changes, or merges. Reply here to discuss or push back — a wrong finding is a bug worth reporting.
srpatcha
left a comment
There was a problem hiding this comment.
Thanks Dipanshu — good hygiene, and it matches what ci.yml:66 already does. I checked each touched job configures with EBLDR_BUILD_TESTS=ON, so the flag can't produce false reds.
One thing right next door with the same "silent pass" problem, for a follow-up if you're interested: .github/workflows/weekly.yml:77-81 runs Valgrind over find build -name "test_*", but the executables are named eboot_test_* (see tests/CMakeLists.txt), so the loop executes nothing, and the || true would hide a failure anyway. #115 restores the proper valgrind_* ctest targets, which would make that shell loop redundant.
Approving.
|
All six red checks here are inherited from
before anything is compiled — which is why every build-side check fails Both are repaired by #115 ( Verified by building the merge result locally: this PR merged with #115 → |
Summary
Make all CTest-based CI jobs fail when no tests are registered.
Motivation
CTest can exit successfully when no tests are registered, which can allow a test-registration or configuration regression to appear as a passing CI job.
The repository already uses
--no-tests=errorinci.yml, and existing regression tests and git history show that dropped test registrations have previously resulted in CI passing with fewer tests than intended.Changes
Add
--no-tests=errorto the five remaining CTest invocations in:build.ymlnightly.ymlrelease.ymlweekly.ymlNo change is made to
ci.ymlbecause it already uses the guard.Verification
EBLDR_BUILD_TESTS=ON.git diff --check.