mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
feat: portals — expose agent-run dev servers to the operator (#122536)
* feat(protocol): add portal methods and event Bump the reviewed protocol owner-module count from 55 to 56. * feat(gateway): add portal service and reverse proxy * feat(agents): add portal tool * fix(gateway): refine portal URL and proxy auth * refactor(gateway): keep portal helper types private * fix(gateway): declare portal transport service * test(gateway): satisfy portal proxy lint * test(gateway): narrow websocket payload types * refactor(protocol): compact portal schema exports * fix(gateway): export portal protocol types * feat(ui): add portals page * docs(gateway): add portals guide * fix(gateway): dial portal targets via localhost dual-stack Vite and other Node >=17 dev servers bind ::1 only for localhost, so a fixed 127.0.0.1 dial 502s on the default path. Use hostname localhost with family autoselection and rewrite Host to match. * fix(gateway): type portal dual-stack connection * fix: satisfy portal integration gates * fix(gateway): isolate portal cookie jars per target Cookies are hostname-scoped, not port-scoped, so the per-port origin split alone let Gateway plugin-auth cookies reach agent-run targets. Forward only cookies carrying this portal's own name prefix (stripped), rewrite target Set-Cookie names to the prefixed form incl. the WS 101 handshake, and drop Domain attributes. * fix(ui): detect unreachable portals behind proxied gateways Probe the portal origin from the browser (no-cors, 4s timeout) and show a recovery notice with the gateway-host URL instead of a dead iframe when only the gateway port is exposed (Serve/Funnel/reverse proxy). Docs: cookie isolation + reachability; zh-CN glossary entry. * test(ui): satisfy portal reachability lint * test(gateway): provide control UI request hosts * chore(protocol): regenerate after rebase * fix(gateway): namespace portal auth cookies by listener * fix(gateway): scope portal token URLs to write-capable clients The portal bearer token rides in the summary url/tokenQuery; portal.list is operator.read and portal.changed fans out to read subscribers, so a read-only client could harvest an openable URL. Make those fields optional, redact them from read-scope list responses, and drop them from every portal.changed broadcast; write/admin clients still receive them and the UI refetches the list on change. * docs(web): list the portals route * fix(gateway): type portal open credentials * docs(gateway): clarify portals PORT/PUBLIC_URL are agent-set Opening a portal creates only the proxy listener; the agent sets PORT and PUBLIC_URL in its own exec command, matching the portal tool contract. Removes the implication of an automatic env handoff. * chore(protocol): regenerate portal models * style(gateway): format portal method-order assertions Rebase union-merge left the portal.list assertion wrapped; oxfmt fits it on one line. * chore(plugin-sdk): refresh API baseline after rebase * chore(plugin-sdk): refresh API baseline after rebase * chore(protocol): refresh portal event order after rebase * chore(plugin-sdk): refresh API baseline after rebase * fix(gateway): pin portal referrer policy to no-referrer The portal URL carries its bearer token in the query, and upstream response headers are copied verbatim, so a target answering with Referrer-Policy: unsafe-url could leak that URL to every third-party origin it references. Force no-referrer after the copy and drop any inbound Referer that still carries the token before forwarding.
This commit is contained in:
committed by
GitHub
parent
4afccbdaa4
commit
cc2fc55f9b
@@ -1 +1 @@
|
||||
{"contentHash":"812e818c8d7c013b2287c4502426123222037a4235e130a69481272912062866","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
|
||||
{"contentHash":"29e2f1aadc64c83fccf94d7fb4747b10e31bbe0922f4806ed3f23d8c1698e6c3","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"contentHash":"f639fea8b8ee53626452bdbce156724b09a3a29bb05a134eb8e8f8fb8062d4da","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
|
||||
{"contentHash":"8407ad2fc13c783155999acdbef231efe60ba69538448a955ff5f10888e51d31","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"contentHash":"02db4abe2f1f4578d438f7afacd68d44114e46b48b9582711e7e10191353e6c5","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
|
||||
{"contentHash":"f44495c27167838fbcdb0ba6afaafd770689e33bb57f725b45b8f9ac20af1565","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"6826237a93cc52b6039fddbd4b4e0e00e82b5c83cbadd36a055a50ab0480879c","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
|
||||
{"contentHash":"29b2feadc45ec3f6c9a7281839142334bf1f8d4ab5fddbed200e99c5e2c51407","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"bc8881a906f40f0a3ede29eb83efc1e4d3e59b62c00154b2480d85d69cbe4010","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
|
||||
{"contentHash":"90a7e6988de562edab9ee28696207bba9fba6d83488dc62d9e0b893ca9603dc6","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"f4b35d03ac9df9788462f3e50b64819ff85aba0245b1a51208a288bd994edb8e","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
|
||||
{"contentHash":"43cedd1b0efa245682de25aa7922045223c58a004bd6a424f1c98968f50396bf","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"80b5ab5fedd16c952c83747f4093db46e49640b3cfa1fdaa5a9727ff31edf0a7","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
|
||||
{"contentHash":"f478b7aa4001f84bb97202d38a75807a67afc2f2c07e074f9121f30298e7493f","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"contentHash":"edfa6b7a219aef521935ac17a20c5cd74e91bf4988eb3fad5ac75fc2e5015596","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
|
||||
{"contentHash":"41d0227914b1eaf4f05dcbc6a92cbe1c824ae9415df8472a5edc0492f5b764ca","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"contentHash":"6490014377554ea6b62c657ab22c53fcec385b4ad24cdfccd95ebd9a79717e59","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
|
||||
{"contentHash":"2e71c5a50c2efb3af7410ffb1cf7b6a6321b4f279c78ab5377fc984321251697","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"b691fcfb34a5f228938d06c50f9f8a26bb63ce06644e9df25f44876601e4cebb","entrypoint":"gateway-runtime","importSpecifier":"openclaw/plugin-sdk/gateway-runtime"}
|
||||
{"contentHash":"067122d86f2c4c36fdebd428eb0183210a4cf3d5ac1ba5f082ae1120b57d14a3","entrypoint":"gateway-runtime","importSpecifier":"openclaw/plugin-sdk/gateway-runtime"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"bb5122c6ac5f4dfe381493b9d128a303108434edca9434ad5528781d005271b8","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
|
||||
{"contentHash":"afddb2d3e7f79b386ed6074f45f85419a0bcae5a6ce49c0157524851c7261d5e","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"9060d4011e1249ca8aa0b01f2e2825d71b29eff14dc84f7f702440dc01e73460","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
|
||||
{"contentHash":"a3a31f78a73ea9159d1779d354b84cff1036741ee3980367c5effc4dd29b1b67","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"contentHash":"a36c13699a318b3fb1b6701ab3280c45e5a4f5ca982cef29778d10af8a5ae97a","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
|
||||
{"contentHash":"64593f3e4ff693f2041d34fd5f3ee6e96795b9b2d49bbd60173d89da7d203494","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"contentHash":"bdf0b57a425cac872d156021006cce6813893bee30e77c5ef4c055343697dba0","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
|
||||
{"contentHash":"9e2037874e2efb4faa53078d6c71089927097ccf08ecb4ba5ca9bd3f4b64414a","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"62f6dc31a2b1789b3667fe16c2d465681aa4c01e2cd9b2a6da062fd995235963","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
|
||||
{"contentHash":"bd3c786f5753a95f03474833f1f5a8872c55ebdf3d541b96c558843e06d3aa44","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"contentHash":"3662752cd7db434787d728355a4fb46e8f4be5b88dece9c29d96225bc02da6db","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
|
||||
{"contentHash":"abf5f77043e2e1b8210541ed48d6ab5e22ec475bf05484d5f6103f82cfdd9f38","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"contentHash":"66ab292503af6befc63d5962f3312a8ebab4ab3bf3a56f47fe4f6a465d7c40b9","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
|
||||
{"contentHash":"9c8a8d0ccdb9961abc35ca210b183a307df34e4ca2b1cf645d5db652cd7f8677","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
|
||||
|
||||
Reference in New Issue
Block a user