Repository navigation
Conversation
Homepage builds a card's link from the route's first hostname plus the path of its first rule's first match, unless gethomepage.dev/href is set. The /mcp bypass from #5881 became the Coroot route's first rule, so the dashboard card opened https://observability.<domain>/mcp, where Coroot answers a browser without a bearer token with 401 "unauthorized". Pin the card to the UI root with gethomepage.dev/href, as the OpenBao, Actual Budget and other routes already do. Rule order does not affect Gateway API routing, so nothing flagged the reorder. Add require-homepage-href-for-non-root-routes, a Deny ValidatingPolicy that requires an explicit href on any opted-in HTTPRoute or Ingress whose derived link is not the site root, with a fixture that includes the shipped Coroot route. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅
|
✅
|
ksail workload validate skips any ValidatingPolicy whose spec strings match the CEL http library identifier, and the Ingress branch's `.?http.?paths` field access matched it. CI therefore warned that the policy was not evaluable offline and never evaluated it against the rendered routes, so a violating route would pass the pull request and only be denied during the merge-group deploy. Neither the repository nor the cluster serves an Ingress, and the tenant role grants only HTTPRoutes, so match HTTPRoutes alone and keep the offline evaluation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai review |
Action performed
|
|
User evaluation at What a user saw, reproduced read-only on prod before the change:
What the change does, observed on the rendered output and the policy engine:
Not reachable before merge: the live card. After the merge-group deploy, I will confirm read-only that the live route carries the 🤖 Generated with Claude Code |

Problem
Since #5881 the Coroot card on the platform dashboard opens
https://observability.platform.devantler.tech/mcp, and the browser showsunauthorizedinstead of the Coroot UI.Root cause
gethomepage.dev/href, Homepage builds a card's link from the route's first hostname plus the path of its first rule's first match (getUrlFromHttpRoute).Exact /mcprule (the agents' MCP bypass) ahead of the catch-all, so the live route'srules[0].matches[0]became/mcp(the API server defaulted the catch-all toPathPrefix /, now in second place)./mcpgoes straight to Coroot, which answers a request without a bearer token with401 unauthorizedandWWW-Authenticate: Bearer realm="coroot". That is correct for the MCP endpoint, but it is not where a dashboard card should point.The MCP route itself works: the agent plugin's API-key connection lists the
platformproject through/mcp.Fix
controllers/coroot/http-route.yaml: setgethomepage.dev/href: https://observability.${domain}, the same pattern the OpenBao, Actual Budget, Hubble and other routes already use.require-homepage-href-for-non-root-routesValidatingPolicy (Deny, background on): an HTTPRoute withgethomepage.dev/enabled: "true"must set a non-emptygethomepage.dev/hrefunless its derived link is the site root. "Root" means a first hostname plus a first-rule first-match path of/that is not aRegularExpressionpath, where an omitted rule, match or path counts as the API server'sPathPrefix /default. Without this guard, any route (including tenant routes in other repositories) could move its card by reordering rules. Ingress is deliberately not matched: nothing in the repository or the cluster serves one, the tenant role grants only HTTPRoutes, and reading an Ingress link needs itshttpfield, which makesksail workload validateskip the whole policy as "uses the CEL http library" (itshttpReferenceheuristic). The first push hit exactly that warning in CI; scoping to HTTPRoute restores the offline evaluation, so a violating route fails the pull request instead of the merge-group deploy.docs/TENANTS.mdtells tenants about the requirement.Live impact of the new policy
Every route with
gethomepage.dev/enabled: "true"in prod today either setshrefor has/as its first path, so after this PR's Coroot change, none would be denied. The Coroot route is applied byinfrastructure-controllersbefore the policy is applied byinfrastructure, so the fixed route is admitted before the policy exists.Validation
kyverno test tests/require-homepage-href-for-non-root-routes: 14/14 pass. The fixture also loads the shipped Coroot route, so removing itshreffails the fixture.hreffails its row (13 pass, 1 fail), and an always-allow policy fails all 6 deny rows.kyverno test ./tests: 916 passed, 0 failed.scripts/validate-kyverno-fixture-evaluation.sh tests: all 101 fixtures evaluate every rule they name.go test ./scripts/validate-policy-actionsandgo run ./scripts/validate-policy-actions: 40 rule actions verified.validate-namingv7.12.0): all conventions satisfied.kubectl kustomizeon the hetzner and dockerinfrastructure/controllersandinfrastructurelayers: the Coroothrefrenders in the prod controllers layer, and the policy renders in both infrastructure layers.🧪 Validate Manifests(ksail workload validatefor both overlays, then the Kubescape scan) validated both changed files and scored 98.87% against the 98% floor. The PR-timeValidate Cluster Policies (services)failure, and the 504s across the queue today, come from the open GitHub incident on unauthenticated download timeouts, not from this change.A live server-side dry-run diff was not possible: the read-only cluster identity lacks
patchon both objects.After deploy, check that the HTTPRoute's
metadata.annotations["gethomepage.dev/href"]is live and that the Coroot card opens the UI.🤖 Generated with Claude Code