fix(apphost): stop MetricsController's extends from 500-ing every route - #1137
Merged
Conversation
`MetricsController extends GenericMetricsController` — an OpenRegister class.
A parent class must be loaded before the child can be declared, and Nextcloud's
router `ReflectionClass`es EVERY controller while matching a route. So with
OpenRegister absent, this did not degrade `/api/metrics`: it returned HTTP 500
for every route in openconnector.
Replaced with the nullable-delegate guard the sibling HealthController in this
same file already uses. A nullable *parameter type* is never autoloaded (only
`extends`/`implements` resolve at class-declaration time), and the service is
built by an explicit factory, so the container never autowires that parameter.
The factory's unconditional `getRegisteredAppContainer('openregister')` — which
throws for an unregistered app — is now behind the same `isInstalled()` guard.
Route name, URL and the admin-only posture (no `#[NoAdminRequired]`) unchanged.
Verified by declaring the class under an autoloader that refuses
`OCA\OpenRegister\*`:
before: FATAL Error "Class GenericMetricsController not found"
after: declares OK, router-style reflection OK, zero OpenRegister autoload
attempts, and index() returns 503 with the Prometheus content type
Also fixes two pre-existing issues found in these files:
- OpenConnectorMetricsProviderTest asserted `assertCount(3, $samples)` in three
tests. #1126 revived sources_total / calls_total / synchronization_runs_total,
making it 6, and left the suite red (2094 tests, 3 failures). Replaced with an
assertion on the metric NAME SET, so the next change fails with a diff that
names the metric instead of "6 does not match 3". Negative-controlled: a wrong
name in the expected set fails all three tests.
- Application::boot() was missing its @SPEC tag (phpcs warning).
Gates, in the PHP 8.4 container against the worktree's own vendor/ (a real
directory, not a symlink to the main checkout):
phpunit 2094 tests, 7552 assertions, 0 failures (was 3 failures)
phpcs 0 errors, 287 warnings (baseline: 0 errors, 288)
phpmd 0 findings (positive-controlled: a probe file yields 3)
psalm exit 0
phpstan No errors
No suppression was added; the one `phpcs:ignore` in the diff is the existing
LegacyNamedAccessor note moved within the rewritten factory (2 before, 2 after).
rubenvdlinde
requested review from
WilcoLouwerse,
bbrands02 and
rjzondervan
as code owners
August 4, 2026 07:39
Contributor
Quality Report — ConductionNL/openconnector @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 153/153 | |||
| npm | ✅ | ✅ 692/692 | |||
| PHPUnit | ⏭️ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ |
Quality workflow — 2026-08-04 07:51 UTC
Download the full PDF report from the workflow artifacts.
Contributor
Author
|
Merging. Verified at job level, not from the rollup — run
|
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.
The defect
MetricsController extends GenericMetricsController— a class owned by OpenRegister.A parent class must be loaded before the child can be declared, and Nextcloud's router
ReflectionClasses every controller while matching a route. So when OpenRegister is absent this did not degrade/api/metrics— it returned HTTP 500 for every route in openconnector. CI does not install OpenRegister.Proven by declaring the class under an autoloader that refuses
OCA\OpenRegister\*:index()Error: Class "…GenericMetricsController" not foundtext/plain; version=0.0.4The fix
The nullable-delegate guard that the sibling
HealthControllerin this same file already uses. A nullable parameter type is never autoloaded — onlyextends/implementsresolve at class-declaration time — and this service is built by an explicit factory, so the container never autowires that parameter. I verified that distinction directly rather than assuming it, since HealthController's docblock asserts it: a nullable typed param naming an absent class produces zero autoload attempts, whileextendson the same class throws.The factory's unconditional
getRegisteredAppContainer('openregister')— which throws for an unregistered app — now sits behind the sameisInstalled()guard.Route name, URL, and the admin-only posture (deliberate absence of
#[NoAdminRequired]) are unchanged.Fleet context
Same defect and same fix as nldesign #208, pipelinq #683, docudesk #369, procest #720. I scanned all 21 repos for controllers whose class header (
extendsorimplements) names an OpenRegister import — openconnector was the last one. The scanner was controlled in both directions against procest's pre-fix and post-fix trees; an earlier version of it returned a false zero on a known-bad tree and was discarded.Two pre-existing issues fixed in the same files
OpenConnectorMetricsProviderTestwas red — three tests assertedassertCount(3, $samples). fix(ci,observability): seed the OR register for Newman; revive 10 metrics dead since the OR cutover #1126 revivedsources_total/calls_total/synchronization_runs_total, making it 6, and left the suite failing. Replaced with an assertion on the metric name set, so the next change fails with a diff that names the metric instead of6 does not match 3. Negative-controlled: a wrong name in the expected set fails all three tests, so the assertion is not vacuous.Application::boot()was missing its@spectag.Gates
PHP 8.4 container, against the worktree's own
vendor/— a real directory, not a symlink to the main checkout, which would silently test the wrong tree.No suppression was added. The single
phpcs:ignorein the diff is the existingLegacyNamedAccessornote moved within the rewritten factory — 2 occurrences before, 2 after.