Skip to content

gateway: fix global Control UI 404s for symlinked wrappers and bundled package roots#40385

Merged
velvet-shark merged 2 commits intomainfrom
codex/pr-39856-clean
Mar 9, 2026
Merged

gateway: fix global Control UI 404s for symlinked wrappers and bundled package roots#40385
velvet-shark merged 2 commits intomainfrom
codex/pr-39856-clean

Conversation

@velvet-shark
Copy link
Member

Summary

  • Problem: bundled Control UI assets can return 404 Not Found for global installs when argv1 points at a symlinked wrapper or when auto-detected package-store layouts expose bundled files through hardlinks.
  • Why it matters: global installs can ship a valid dashboard but still fail at GET /, while the previous package-root heuristic also widened the file-read boundary for configured roots.
  • What changed: make Control UI root discovery symlink-aware, classify auto-detected package-proven roots as bundled, and allow hardlinks only for those bundled roots.
  • What did NOT change (scope boundary): explicit gateway.controlUi.root overrides still stay on the strict hardlink boundary and continue to reject hardlinked assets.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • Auto-detected global/package installs can serve the bundled Control UI again when the executable is reached through a symlinked wrapper or when bundled files are hardlinked in a package-store layout.
  • Explicit gateway.controlUi.root overrides remain strict and still reject hardlinked assets.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 22 + pnpm
  • Model/provider: N/A
  • Integration/channel (if any): Gateway Control UI HTTP handler
  • Relevant config (redacted): default auto-root plus explicit gateway.controlUi.root fixtures

Steps

  1. Point Control UI discovery at a symlinked global wrapper or an auto-detected package root whose bundled files are hardlinked.
  2. Request GET / or a bundled asset.
  3. Repeat with an explicit gateway.controlUi.root fixture that points at a hardlinked package-store Control UI root.

Expected

  • Auto-detected bundled roots serve the dashboard and bundled assets.
  • Explicit configured roots still reject hardlinked assets.

Actual

  • Verified by focused regression tests below.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: symlinked-wrapper asset discovery, bundled-vs-resolved hardlink handling, explicit configured-root rejection.
  • Edge cases checked: hardlinked index.html, hardlinked bundled assets, non-package fallback roots, SPA fallback under bundled roots.
  • What you did not verify: full repo-wide gates on this clean branch.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert this PR or keep using an explicit custom Control UI root with non-hardlinked assets.
  • Files/config to restore: src/infra/control-ui-assets.ts, src/gateway/server.impl.ts, src/gateway/control-ui.ts
  • Known bad symptoms reviewers should watch for: bundled global installs still returning 404, or configured custom roots unexpectedly serving hardlinked files.

Risks and Mitigations

  • Risk: auto-detected bundled roots could be misclassified if package provenance logic is too loose.
    • Mitigation: root classification is package-proven only and has dedicated regression tests for package and fallback roots.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 9, 2026

Greptile Summary

This PR fixes Control UI 404 Not Found errors for global installs by making root discovery symlink-aware and introducing a "bundled" root classification that permits hardlinked assets for package-proven (auto-detected) installs, while keeping explicit gateway.controlUi.root overrides on the strict hardlink-rejection boundary.

Key changes:

  • resolveControlUiDistIndexPath and resolveControlUiRootSync now call realpathSync on argv1 so symlinked global wrappers (e.g., Bun, pnpm shims) correctly resolve to the package's dist/control-ui directory.
  • New isPackageProvenControlUiRootSync utility classifies a resolved root as "package-proven" by comparing it (via realpathSync) to the package root's dist/control-ui.
  • New "bundled" discriminant on ControlUiRootState; server.impl.ts pre-computes this at startup so no per-request filesystem cost is incurred in production.
  • resolveSafeControlUiFile now accepts rejectHardlinks and passes it through to openBoundaryFileSync, enabling hardlinks only for bundled roots.
  • Explicit controlUiRootOverride paths continue to receive kind: "resolved" and always reject hardlinks — the security boundary is intact.
  • Test coverage is thorough: symlinked-wrapper discovery, bundled vs. resolved hardlink handling, configured-root rejection, and package-proven vs. fallback root classification are all exercised.

Confidence Score: 5/5

  • Safe to merge. Security boundary for explicit root overrides is maintained; hardlinks are rejected for configured roots and allowed only for package-proven auto-detected roots.
  • The PR correctly fixes the 404 errors for symlinked global wrappers and bundled installs while maintaining the strict hardlink-rejection boundary for explicitly configured Control UI roots. The symlink resolution uses realpathSync appropriately, the bundled vs. resolved classification is sound, and production performance is optimized through pre-computation at startup. Test coverage is comprehensive and exercises the key scenarios.
  • No files require special attention.

Last reviewed commit: d025bea

@velvet-shark
Copy link
Member Author

Merged via squash.

Thanks @velvet-shark!

GordonSH-oss pushed a commit to GordonSH-oss/openclaw that referenced this pull request Mar 9, 2026
…d package roots (openclaw#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
vincentkoc pushed a commit that referenced this pull request Mar 9, 2026
…d package roots (#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
jenawant pushed a commit to jenawant/openclaw that referenced this pull request Mar 10, 2026
…d package roots (openclaw#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
sauerdaniel pushed a commit to sauerdaniel/openclaw that referenced this pull request Mar 11, 2026
…d package roots (openclaw#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
Moshiii pushed a commit to Moshiii/openclaw that referenced this pull request Mar 11, 2026
…d package roots (openclaw#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
Moshiii pushed a commit to Moshiii/openclaw that referenced this pull request Mar 11, 2026
…d package roots (openclaw#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
…d package roots (openclaw#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
Taskle pushed a commit to Taskle/openclaw that referenced this pull request Mar 14, 2026
…d package roots (openclaw#40385)

Merged via squash.

Prepared head SHA: 567b3ed
Co-authored-by: velvet-shark <[email protected]>
Co-authored-by: velvet-shark <[email protected]>
Reviewed-by: @velvet-shark
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui cli CLI command changes gateway Gateway runtime maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Global installation via Bun results in 404 Not Found on native Dashboard URL (Port 18789)

1 participant