Skip to content

Decouple resources overview from chorus - #118

Merged
pjcdawkins merged 1 commit into
upsun:mainfrom
mharacewiat:feat/obs-2425-decouple-resources-overview-from-chorus
Sep 24, 2026
Merged

pjcdawkins merged 1 commit into
upsun:mainfrom
mharacewiat:feat/obs-2425-decouple-resources-overview-from-chorus

Conversation

@mharacewiat

Copy link
Copy Markdown
Contributor

Copilot AI review requested due to automatic review settings June 26, 2026 09:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the legacy CLI metrics flow to obtain the “resources overview” URL via the environment’s /observability/ entrypoint response, rather than relying on the #observability-pipeline link (decoupling the overview lookup from chorus-specific linkage).

Changes:

  • Replace #observability-pipeline link usage with a GET to {environmentUri}/observability/ to discover _links.resources_overview.href.
  • Adjust return docstring to reflect returning a URL (or false) when unavailable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread legacy/src/Command/Metrics/MetricsCommandBase.php
Comment thread legacy/src/Command/Metrics/MetricsCommandBase.php
@mharacewiat
mharacewiat force-pushed the feat/obs-2425-decouple-resources-overview-from-chorus branch from 45ce22e to 908b343 Compare June 26, 2026 09:28

@pjcdawkins pjcdawkins left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. The change itself is sound: I checked the happy path against the live API and the observability/ entrypoint returns an absolute href and responds 200 for inactive and paused environments, so the discovery works. The earlier Copilot points (404-only handling, the is_array() guard) are addressed in 908b343. All four checks pass.

Nothing here is blocking. There is one question that needs a maintainer decision rather than a code fix, and three smaller items.

The decision: host trust

MetricsCommandBase.php:135 follows the returned href verbatim with the OAuth-authenticated client, with no host check. Two pieces of context that make this worth an explicit call rather than a nit:

  • vendor/platformsh/oauth2/src/GuzzleMiddleware.php:181-185 attaches the bearer token to every request made through Api::getHttpClient(), regardless of host.
  • ApiResourceBase::makeAbsoluteUrl() (vendor/platformsh/client/src/Model/ApiResourceBase.php:568-581) deliberately overrides an absolute link host with the resource's base host, specifically so that link hrefs cannot redirect requests elsewhere.

So the client library has an existing guard for exactly this pattern, and this code path sits outside it: the entrypoint is fetched from the region and the host it returns is then trusted for a token-bearing request. There is precedent for following body-supplied hrefs (TeamListCommand.php:187), so this is hardening rather than a new class of issue — but it is a region-to-central-API hop, so it should be a deliberate choice.

Smaller items

  • MetricsCommandBase.php:135 — the href is mixed while the method declares false|string. Under declare(strict_types=1) a non-string href raises a TypeError instead of taking the handled "not available" path. PHPStan will not catch this below level 9 (checkExplicitMixed is off, and there is no baseline entry for this file). Folding is_string(...) into the existing guard covers it.
  • MetricsCommandBase.php:169 — the query string is still appended by concatenation, but the URL is now server-controlled. An href carrying its own query would produce ...?view=default?range=600. Latent today since the current response has no query part; building the request with Guzzle's query option would remove the class of problem.
  • MetricsCommandBase.php:117 — one extra serial, uncached round trip per metrics invocation, and a transient 5xx on the entrypoint now aborts the command even when the metrics endpoint itself is healthy. The URL is stable per environment and Api already has a cache.

Tests

None added. For context rather than criticism: legacy/tests/ has no Command/Metrics/ coverage and no Guzzle MockHandler infrastructure at all, so this matches existing practice rather than regressing it. The new branching is pure logic and would be testable if the discovery were extracted out of the private method.

One thing I did not check: whether the observability entrypoint is present for every region and vendor this binary ships to. The fallback is "metrics not available", so it is worth confirming on the rollout side.


Review by Claude Code.

@pjcdawkins
pjcdawkins merged commit 0edd18f into upsun:main Sep 24, 2026
4 checks passed
pjcdawkins added a commit that referenced this pull request Sep 24, 2026
Resolve conflicts with the --latest fix (#165) and the observability
entrypoint lookup (#118):

- MetricsCommandBase: keep both STORAGE_MOUNTPOINT and
  LATEST_SETTLE_TIME.
- Move the storage tests to metrics_storage_test.go, next to the
  --latest tests in metrics_test.go.
- Serve the observability entrypoint (_links.resources_overview) in both
  tests' mocks, as the resources overview URL is now discovered there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pjcdawkins added a commit that referenced this pull request Sep 24, 2026
Since #118, the metrics commands find the resources overview URL via the
"resources_overview" link from GET {environment}/observability/, instead
of the environment's "#observability-pipeline" link. TestMetricsLatest
(#165) was written against the old lookup, so it failed on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pjcdawkins added a commit that referenced this pull request Sep 24, 2026
…#167)

Since #118, the metrics commands discover the resources overview URL via
GET {environment}/observability/ instead of the #observability-pipeline
link. TestMetricsLatest (#165) still mocked the old link, so the CLI got
a 404 and failed with "Observability API link not found".

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
pjcdawkins added a commit that referenced this pull request Sep 24, 2026
… plans (#50)

* fix: Clarify why certain functions are not available for upsun fixed

* Update error message for unsupported API usage

* fix(legacy): mention Upsun Fixed only for projects in Fixed organizations

The "flexible resources API is not enabled" error is shared by all the
resources:* commands, so move it to ResourcesUtil and use it everywhere
instead of only in resources:build:get.

A disabled sizing API does not by itself mean the project is on Upsun
Fixed, so the Fixed note is now only shown when the project's
organization has the "fixed" type. If the organization cannot be loaded
(e.g. the user has no access to it), the note is skipped.

The docs link uses the docs.upsun.com/anchors/fixed/ redirect, like
other Fixed links in the CLI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(metrics): mock the observability entrypoint in TestMetricsLatest

Since #118, the metrics commands find the resources overview URL via the
"resources_overview" link from GET {environment}/observability/, instead
of the environment's "#observability-pipeline" link. TestMetricsLatest
(#165) was written against the old lookup, so it failed on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(legacy): configure the Fixed docs URL and avoid extra API calls

Address review feedback on the sizing API error:

- Read the docs link from a new service.fixed_docs_url config key, and
  drop the "Upsun" brand from the message, so vendor builds without the
  key show no Fixed note.
- Skip the organization lookup when api.organizations is disabled.
- Read the project's organization without lazy loading, so a missing
  property cannot trigger an uncaught API request.
- Assert on the note and URL in the test, rather than any "fixed" text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Matthias Van Woensel <3532563+matthiaz@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants