13 Commits

Author SHA1 Message Date
Ruben Fiszel 154f8f461e feat(debugger): install debug session deps from the instance registry settings (#10550)
* feat(debugger): install debug session deps from the instance registry settings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(debugger): keep install-time registry credentials out of the session-visible tree

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: drop em dashes from the debugger registry docs and comments

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(debugger): stop installing for a session that went away during the settings fetch

Also serves nativets sessions the npm settings their installer reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 20:16:38 +00:00
Ruben Fiszel a5423a81ca fix(debugger): confine prepare-deps under nsjail in both language paths (#10546)
`windmill prepare-deps` was spawned with Bun's raw `spawn` in both the Python and
the TypeScript session, bypassing the nsjail wrapping the debugged script itself
gets. With ENABLE_NSJAIL=true, `uv pip install` (source distributions run their
build backend) and `bun install` (postinstall scripts) therefore executed
package-supplied code unconfined, next to the LSP, multiplayer and gateway
services in the windmill-extra container.

Both installers now go through the same nsjail wrapper as the debuggee, which the
two files no longer build separately. The jail keeps the environment
(`keep_env`), which is what carries the registry credentials and CA settings into
the installer; the debugged script's environment is unchanged and still holds
neither.

Killing the installer also did not reap the `uv` or `bun` it had spawned: those
were reparented to init and kept downloading, so both the timeout and the
cancel-on-disconnect only half-worked. The installer now runs in its own process
group and is signalled as a group, reading the group id back from /proc rather
than assuming it, since a group kill aimed at the service's own group would take
down every service in the container.

Two things that cancellation exposed: a kill was reported to the client as an
install failure, since it ends the read with nothing to parse - blaming the user
for their own Stop; and the standalone Bun server's close handler only dropped
the session from its map, so nothing there was ever cleaned up. The teardown flag
is also scoped to a launch rather than the session, because cleanup() runs when a
program finishes normally too.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 19:08:04 +00:00
Ruben Fiszel 74c418570b fix: forward TLS trust roots to debug sessions and honor INIT_SCRIPT on windmill_extra (#10532)
* fix: forward proxy and TLS settings to debugger subprocesses

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: reach uv and the bun debugger with the forwarded network settings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: map every CA variable spelling onto the one uv reads

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: keep package-index credentials out of debugged user code

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: install debugger dependencies outside the interpreter running user code

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: sandbox and bound the debugger dependency installer

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: correct the installer timeout rationale

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: scope the uv --cert note to the commands prepare-deps runs

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: build the debug venv against the interpreter that runs the script

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: do not start the debuggee for a session that already went away

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: remove the debug script when the session is gone before it starts

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 16:25:52 +00:00
Ruben Fiszel 29e179f787 fix(debugger): report python debugger dependency install failures instead of timing out (#10531)
* fix: report python debugger dependency install failures instead of timing out

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: surface swallowed installer errors and stream debugger prepare progress

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: reap the python debugger on a failed launch and bound prepare-deps

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: match uv failure output by stripping progress instead of matching errors

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: treat uv build, download and warning lines as install progress

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 13:46:36 +02:00
Ruben Fiszel 7d153d5750 fix(debugger): pass python index settings to prepare-deps and report failures (#10533)
* fix: honor python index settings in prepare-deps and report install failures

* fix: forward python registry env to the debugger's prepare-deps

* fix: scope registry credentials to the prepare-deps subprocess

* fix: install python debug dependencies from the service, not the session

* fix: bound the debugger dependency install and keep the proxy bypass default

* docs: name the nsjail config that isolates debug sessions
2026-08-05 13:43:12 +02:00
Ruben Fiszel c0768de0ac fix: close unauthenticated DAP debugger program-mode launch bypass (#9829)
The /ws_debug debugger WebSocket gated JWT signature verification on inline
`code` being present (`if (code && REQUIRE_SIGNED_REQUESTS)`), so a
`program`-mode launch (naming an arbitrary server-side file path that is read
and executed) skipped verification entirely — even with
REQUIRE_SIGNED_DEBUG_REQUESTS=true. The WS handshake also performed no Origin
check, allowing cross-origin (CSWSH) drive-by from a malicious page.

- Enforce signing on every launch in both handlers (Python + Bun/TS): reject
  program-mode outright and require+verify a token for inline code.
- Add opt-in DEBUG_ALLOWED_ORIGINS allowlist enforced at the WS handshake.
- Default docker-compose REQUIRE_SIGNED_DEBUG_REQUESTS to true.
- Update THREAT_MODEL T8/EP15 to reflect the root cause and mitigation.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 11:49:27 +02:00
Ruben Fiszel e0857421aa handle /ws_debug/health in debugger and add request logging (#8426)
- Fix debugger HTTP health endpoint to also match /ws_debug/health
  (ingress forwards the full path, not just /health)
- Add request logging to all three extra services (LSP, multiplayer,
  debugger) for HTTP and WebSocket ping/upgrade events

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 09:21:38 +00:00
Ruben Fiszel 372023e995 feat: add ws_base_url instance setting for WebSocket URL override (#8405)
* feat: add ws_base_url instance setting to override WebSocket base URL

Allow deployments behind reverse proxies to route WebSocket traffic
(LSP, debugger, multiplayer) to a different host/port than the main
frontend via a new instance setting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: move ws_base_url to Advanced section with toggle and connectivity test

- Move setting from Core to Advanced > WebSocket section
- Render as toggle "Custom websocket base url from frontend to
  multiplayer/lsp/debugger" with conditional URL text field
- Add Test connectivity button (always visible) that checks HTTP health
  and WebSocket ping for all three services (LSP, Multiplayer, Debugger)
- Add /ws/ping and /ws/health endpoints to LSP service
- Add /ws_mp/health HTTP and __ping__ WS handlers to multiplayer service
- Add /ping WS handler to debugger service
- Add CORS headers to health endpoints for cross-origin testing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: toggle enabled check and testWs promise resolution

- Fix enabled derived to check only for null (not empty string),
  otherwise the toggle never turns on since toggleEnabled sets ''
- Fix testWs onclose handler to resolve(false) so the promise
  doesn't hang if the server closes without sending a message

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: make connectivity test work with existing services

- HTTP test: accept plain text "ok"/"okay" (old services) in addition
  to JSON {"status": "ok"} (new services), reject HTML (SPA fallback)
- WS test: resolve on onopen (connection established) instead of
  waiting for a specific pong message, so the test works even with
  services that don't have the new /ping handler yet

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 12:48:59 +00:00
Ruben Fiszel 40d00734f3 fix: improve debugger behavior 2026-01-14 14:45:23 +00:00
Ruben Fiszel 14cfce3fd6 fix(debugger): fix nsjail sandbox for debugger execution
Multiple fixes to make nsjail work correctly:

1. Use absolute paths for python3 and bun binaries (/usr/bin/python3,
   /usr/bin/bun) since nsjail's execve doesn't use PATH

2. Update cwd to use temp directory when code is written there, so
   nsjail can find the script files (was using /debugger as cwd before)

3. Bind-mount /tmp from host instead of using tmpfs, so the temp
   directories with scripts are accessible inside the sandbox

4. Add /debugger directory mount so Python debugger server script
   is accessible inside nsjail

5. Add PATH environment variable to nsjail config

All debugger tests now pass with ENABLE_NSJAIL=true.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 11:43:38 +00:00
Ruben Fiszel 8d005b030f fix(debugger): properly decode base64url public key from JWKS
The public key decoding from JWKS was missing base64url padding, causing
JWT signature verification to fail with "invalid jwt token" errors in
production. The `jwk.x` value needs proper padding before base64 decoding.

Fixed by using the existing `base64urlDecode` helper function which
correctly adds padding, instead of manually doing the conversion.

This resolves JWT verification failures when REQUIRE_SIGNED_DEBUG_REQUESTS
is enabled.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 19:47:31 +00:00
Ruben Fiszel f8cbf15d86 refactor: change debugger port from 5679 to 3003
Updates the debugger service to use port 3003 instead of 5679 across
all configuration files, documentation, and code references. This aligns
the debugger with the other windmill-extra services which use ports
3001 (LSP) and 3002 (Multiplayer).

Changes:
- docker-compose.yml: Update port exposure and add DEBUGGER_PORT env
- docker/entrypoint-extra.sh: Change default port from 5679 to 3003
- debugger/dap_debug_service.ts: Update default port in code and docs
- debugger/README.md: Update port documentation
- debugger/test_debug_service.ts: Update test URLs
- docker/test_windmill_extra.ts: Update test configuration
- .github/workflows/publish_extra.yml: Update test container ports
- frontend/src/lib/components/debug/*: Update frontend examples and defaults

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 17:58:12 +00:00
Ruben Fiszel 4451a37999 feat: debuggers for python and bun v0 (#7546) 2026-01-13 15:20:06 +00:00