Commit Graph

13941 Commits

Author SHA1 Message Date
Guilhem Lemouel 2fdafdddaf feat(ai): check raw app frontend compilation from the chat
get_lint_errors on a raw app without a runnable key now compiles the app's
frontend files and reports where the build broke, so editing app files can
be checked the same way editing a runnable already was. A frontend is a
bundle rather than a set of independent documents, so there is no language
service to query per file — only the compiler's verdict, which also means
files unreachable from the entry point are not covered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 14:26:30 +02:00
Guilhem Lemouel aaa7601950 fix(ai): correct headless lint ownership, staleness and timeouts
Review findings on the headless linter:

- An editor can adopt a model headless linting created, so attachment now
  decides who owns a buffer rather than who created it. The editor likewise
  applies its own content when adopting an existing model, instead of
  displaying whatever was last linted.
- Markers are cleared when an owned model is rewritten: they outlive the
  content they describe, and a matching count let the settle loop return
  the previous version's diagnostics.
- Eviction no longer drops the URI it is keeping, which had left a live
  model untracked and subsequently treated as belonging to an editor.
- A language server that stalls is named in the result rather than
  contributing an empty list, and no longer discards what other servers
  already reported.
- A client abandoned at its deadline is stopped, so it cannot keep holding
  the global command names every later lint of that language needs.
- Deno's import map is built from the path its document actually has.
- Pre-lint network calls are bounded; lints of one URI queue behind each
  other, so a hung request would otherwise wedge that item indefinitely.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 14:18:45 +02:00
Guilhem Lemouel 0236c3b145 feat(ai): headless linting for python, go, deno and bash
Extends get_lint_errors beyond the TypeScript worker to the language-server
languages. These servers are driven directly rather than through the editor's
clients: pyright and gopls implement LSP 3.17 pull diagnostics and only get
asked for documents visible in an editor, so headless the request has to be
made explicitly. Servers that answer with nothing are still given a bounded
window to publish instead, which is how ruff reports.

A server whose client cannot start — its global command names are taken when
an editor is already running one — is named in the result instead of silently
shrinking it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 13:29:17 +02:00
Guilhem Lemouel f5b9dc7f5c refactor(editor): extract language server configuration
Diagnostics for python, go, deno and shell are decided by which server runs
and with which initialization options, so headless linting has to build its
clients from the same descriptors. Move them to lint/lspLanguageConfig.ts;
the editor keeps owning the websocket lifecycle and reconnection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 12:59:37 +02:00
Guilhem Lemouel 11b58cacb5 feat(ai): get_lint_errors tool for global chat
Global chat edits drafts with no editor mounted, so until now it had no way
to type-check what it wrote. The tool resolves draft or deployed code for a
script, an inline flow module, or a raw app backend runnable, lints it
headlessly at the URI the editor would use, and reports unsupported
languages explicitly rather than a misleading clean result.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 12:48:50 +02:00
Guilhem Lemouel 7147261450 feat(ai): headless TypeScript lint service
Lints script, flow-step and raw-app runnable code with no editor mounted, by
driving the same Monaco model, extra libs and acquired types an editor would.
Settling waits for the worker's own diagnostic count rather than a fixed
sleep, which also terminates immediately on clean code, where no marker
change event is ever emitted. Editor.getLintErrors now reads markers through
the same helper, so the two cannot drift apart.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 12:43:39 +02:00
Guilhem Lemouel e47d760eba refactor(editor): extract ATA setup and lsp token root
Headless linting needs the same acquired types as the editor, npm
declarations and relative-import models alike. Move the ATA delegate and
token root to lint/typescriptAta.ts; the editor keeps its trigger logic and
supplies the model-revalidation nudge via onLocalFileRegistered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 12:38:04 +02:00
Guilhem Lemouel 35f3196c4a refactor(editor): extract typescript extra-libs registration
Headless linting must register the same rt.d.ts resource-type namespace and
custom windmill-client declarations as a mounted editor, since diagnostics
depend on them. Move the apply bodies to lint/typescriptExtraLibs.ts; the
editor keeps its reactive resource() wrapper around the fetch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 12:35:06 +02:00
Guilhem Lemouel b89e082e87 refactor(editor): extract Monaco model path/URI computation
Headless linting needs to derive the exact model URI the editor uses;
computeUri/computePath were component-local closures over scriptLang and
lang. Move them to lint/monacoUri.ts with those as explicit parameters.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 12:30:13 +02:00
hugocasa 7b813d1f74 fix(frontend): sanitize job result markup, gate it on unsandboxed public apps (#10127)
* fix(frontend): sanitize html and svg result rendering

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

* chore(frontend): add dompurify to lockfile root deps

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

* fix(frontend): keep sanitizing rich results on public app surfaces

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

* feat(frontend): gate risky app markup on unsandboxed public surfaces

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

* fix(frontend): derive app markup isolation from the real origin

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

* style(frontend): use the design-system danger alert for the markup gate

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 15:49:20 +02:00
hugocasa 24750e6ef1 fix(raw-apps): prevent and surface the silent blank screen from an unmounted #root (#10150)
* fix(raw-apps): prevent and surface the silent blank screen from an unmounted #root

An `index.tsx` written as a bare `export default function App() {...}` with
no mount call builds and runs without throwing: the preview executes the
bundle against an empty `<div id="root">` and auto-renders nothing, so the
JSX never runs, nothing reaches the console or the runtime-error overlay,
and the app is blank with no diagnostic.

Prevent it: the raw-app system prompt and the in-chat app prompt now state
that `index.tsx` is the mount entrypoint, show the mount shim for React,
Svelte and Vue, and call out that a bare component fails silently.

Surface it: when a build still mounts nothing, the preview harness posts
`emptyRender` and the editor shows an error overlay naming the missing
call. The harness reports only when nothing is on screen AND the app never
looked `#root` up, so an app that mounted but paints nothing yet (a fetch
in flight, an unresolved Suspense) is never flagged; `renderAppeared`
withdraws the overlay if a deferred mount lands late.

The handlers stay dormant until the builder tarball that emits these
messages is pinned via `ui_builder_artifact.json`.

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

* chore(raw-apps): pin the UI builder artifact that emits emptyRender

Activates the "Nothing was mounted" overlay: the pinned tarball predates
the harness change, so the host handlers were dormant until now.

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

* chore: drop a screenshot accidentally committed at the repo root

Not referenced anywhere; the PR's screenshots are hosted externally.

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

* fix(raw-apps): make the unmounted-app guidance framework-aware

The detector fires for every raw-app framework, but the overlay and the
prompts named React's `index.tsx` and `createRoot` unconditionally. Svelte
and Vue apps mount from `index.ts` via `mount` / `createApp`, so the
guidance pointed at a nonexistent entrypoint and an unavailable API.

Derive the entrypoint and mount call from the app's files, keyed off file
extensions rather than the template filenames, which users rename.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 15:48:50 +02:00
Guilhem fa03984a14 fix(ai): show the question in askUserQuestion tool-call labels (#10153) 2026-07-16 15:48:24 +02:00
Diego Imbert 7d5009e392 fix: heartbeat job ping during s3object materialization in SQL executors (#10152)
* fix: heartbeat job ping during s3object materialization in SQL executors

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KrFtZjXc8GB6VtSMVJFXjE

* chore: update ee-repo-ref.txt

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KrFtZjXc8GB6VtSMVJFXjE

* chore: update ee-repo-ref to e19948fa2974a7d89bec12957fc6d9fa0a421da8

This commit updates the EE repository reference after PR #668 was merged in windmill-ee-private.

Previous ee-repo-ref: a3828dcd67f026c0e983a1a5dc5c5b33af3c3120

New ee-repo-ref: e19948fa2974a7d89bec12957fc6d9fa0a421da8

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-07-16 15:48:11 +02:00
Ruben Fiszel 3bd9f05938 fix(alerts): identify server replica in low-disk alert + per-host dedup tag (#10143)
* fix(alerts): identify server replica in low-disk alert + per-host dedup tag

The server-mode low-disk alert keyed its dedup tag on the mountpoint alone,
so `simple_alert_helper` mapped every server replica onto a single alert row
per mountpoint. With more than one replica that row flaps every monitor pass:
a replica seeing low disk raises the alert while a replica seeing healthy disk
recovers it. The alert text also could not say which replica tripped.

The fix lives in windmill-ee-private (`low_disk_alerts` in
windmill-common/src/ee.rs) and appends the hostname to both the message and
the dedup tag, mirroring the worker branch.

Also add a regression test pinning the server tag as per-host, and correct the
monitor cadence comments: iterations are LISTEN_NEW_EVENTS_INTERVAL_SEC
(10s by default), not 30s, so "~60s (2 iterations * 30s)" was wrong on both
factors.

* fix(alerts): widen healthchecks.check_type so per-host disk tags fit

Alert tags embed a mountpoint and a hostname, both unbounded, but check_type
was varchar(50). create_alert only logs the insert error while the
notification still fires, so an overflowing tag re-alerts every monitor pass
and never records recovery state.

The server tag overflows for ordinary pod-length hostnames, and the existing
worker tag already overflows for every tracked mount except "/". Widening the
column fixes both; bounding the hostname would not, since the mountpoint alone
can consume the budget.

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

* chore: update ee-repo-ref to b3d01f2c0d2c0714ae95b8a348af22b0fcc30ee4

This commit updates the EE repository reference after PR #666 was merged in windmill-ee-private.

Previous ee-repo-ref: ccd1e42cf6b2d051ca17074fbdf5b80a46cffe0f

New ee-repo-ref: b3d01f2c0d2c0714ae95b8a348af22b0fcc30ee4

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-16 15:21:54 +02:00
Ruben Fiszel 4e0fd4db55 feat(alerts): include disk total and top consumers in low-disk alert (#10144)
* feat(alerts): include disk total and top consumers in low-disk alert

Point ee-repo-ref at the companion windmill-ee-private commit.

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

* fix(alerts): pass alert message lazily from the min-version check

simple_alert_helper now takes the error message as a future so callers can
put diagnostic work behind it. Update this call site and point ee-repo-ref
at the companion windmill-ee-private commit.

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

* chore: point ee-repo-ref at rebased EE branch

Rebase onto EE main so the pin keeps the SAML metadata fixes (394ad23)
that the previous ref carried, and pick up the mount-scoped consumer walk.

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

* chore: bump ee-repo-ref for bind-mounted file exclusion

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

* chore: update ee-repo-ref to 4d7aafdba33a879b3c60d390c960e57679da9e87

This commit updates the EE repository reference after PR #667 was merged in windmill-ee-private.

Previous ee-repo-ref: 08d3aa4c5bf630d15a28289cca62a0f1da7b7386

New ee-repo-ref: 4d7aafdba33a879b3c60d390c960e57679da9e87

Automated by sync-ee-ref workflow.

* chore: point ee-repo-ref at the merged EE work plus the test fix

ee#667 squash-merged, so the previous pin was a branch commit no longer
reachable from EE main. Point at ee#669, which branches from EE main and
carries the /proc test-portability fix.

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

* chore: update ee-repo-ref to d8a7ac6ae97642a7f4928e6be6846a32dabf4e26

This commit updates the EE repository reference after PR #669 was merged in windmill-ee-private.

Previous ee-repo-ref: 5526aedd73654b9aa4086dae0441b9687ff6415d

New ee-repo-ref: d8a7ac6ae97642a7f4928e6be6846a32dabf4e26

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-16 14:58:26 +02:00
Guilhem 568dbbee85 fix(frontend): show friendly draft path for draft-only items in pickers (#10136)
* fix(frontend): show friendly draft path for draft-only items in pickers

* fix(frontend): dedupe current draft item and scope tab picker by friendly path

* fix(frontend): key live draft picker entries by storage path

* fix(frontend): fall back to the current leaf when the picker highlight key vanishes

* fix(frontend): remount session tab picker when the friendly scope arrives

* fix(frontend): stamp staged tab path for deployed items with undeployed renames

* fix(frontend): expose staged flow/raw-app renames through the live draft registration
2026-07-16 14:56:57 +02:00
Guilhem 7fda6a0534 feat(frontend): flatten workspace pickers, whole-tab picker trigger (#10145)
* fix(frontend): open session preview picker from whole tab, anchor to tab edge

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(frontend): flatten session preview picker to workspace home level

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(frontend): flatten chat context picker workspace tree

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): show root loading state in flat drill pickers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): make tab-strip keyboard activation work inside dnd zones

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): return focus to tab after active-tab picker closes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): move focus with selection on arrow-key tab navigation

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 13:36:45 +02:00
Guilhem cc305b1d97 refactor(frontend): reorder sidebar settings menu, move logout to user submenu (#10149)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 13:36:01 +02:00
hugocasa 4ee1d32101 feat: display openai reasoning summaries in ai chat (#10147)
* feat(frontend): display openai reasoning summaries in ai chat with unverified-org fallback

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): scope hidden-thinking hint per workspace/provider and skip summary on explicit reasoning-off

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): compose responses fallbacks in either error order and track all unavailable summary keys

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 13:31:10 +02:00
hugocasa 0694b84da7 fix(frontend): surface real tool call errors in AI chat (#10146) 2026-07-16 11:19:19 +02:00
AlexRV12 0ea570570e feat(ai-sessions): CRUD markdown artifacts in sessions (#10046)
* feat: add IndexedDB persistence layer for AI-chat artifacts

* feat: add reactive store for AI-chat artifacts

* feat: add artifact chat tools and wire store lifecycle

* feat: add markdown artifact viewer with source toggle

* feat: surface session artifacts in the preview panel and chat list

* feat: tell the copilot when to use artifacts in the session prompt

* test(ai_evals): add artifact case and wire artifact helpers for session context

* fix(copilot): keep in-memory artifacts across same-session resyncs

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

* feat: unify session composer edits/artifacts/jobs into a status line

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

* feat: add an artifacts section to the session preview picker

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: share markdown prose presets and restyle the artifact viewer

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: unify session status popovers into one keyboard-navigable shell

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: reset first-block top margin in all markdown prose presets

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: open the preview picker on the artifacts branch for an active artifact

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: keep artifact picker scope independent of branch hydration state

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Guilhem Lemouel <guilhemlemouel@gmail.com>
2026-07-16 11:17:20 +02:00
Ruben Fiszel a935d06c8e chore(main): release 1.760.1 (#10142)
* chore(main): release 1.760.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.760.1
2026-07-15 21:29:39 +02:00
Ruben Fiszel 8c725d9e44 fix(apps): honor presigned S3 signature on app display/preview routes (#10141)
The app provenance gate short-circuits on a valid presigned signature, but only the raw download_s3_file route parsed it. The parquet/csv/table-count/file-preview/metadata routes discarded sig/exp and always fell through to the provenance gate, so a presigned S3 object rendered as a table showed "File restricted" for any viewer who did not produce it. Thread sig/exp through every apps_u S3 display route and forward the presigned bearer from ParqetCsvTableRenderer/DisplayResult.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 21:18:15 +02:00
Ruben Fiszel 2092155191 chore(main): release 1.760.0 (#10128)
* chore(main): release 1.760.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.760.0
2026-07-15 18:00:53 +02:00
Guilhem 9705d60284 fix(frontend): keep session-exit URL clean by syncing new_draft strip with the router (#10101)
* fix(frontend): keep session-exit URL clean by syncing new_draft strip with the router

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

* chore(frontend): correct replaceState comment and test-mock wording per review

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(frontend): correct replaceState comment and drop drafting-history phrasing

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:56:19 +02:00
Guilhem af177cefe0 fix(frontend): graceful small-screen timeframe picker on the runs page (#10073)
* fix(frontend): prevent runs timeframe calendar popover overflow on small screens

The Runs page timeframe picker rendered its popover as a wide 3-column row
(preset list + two side-by-side calendars). With the right-aligned trigger and
a center-anchored `bottom` placement, the popup ran off the right edge on
narrow viewports.

Anchor the popover to the right edge (`placement="bottom-end"`) and make its
content reflow to a vertical stack below the `sm` breakpoint, capped at
`max-w-[calc(100vw-2rem)] max-h-[80vh] overflow-auto` so it can never exceed the
viewport. The desktop side-by-side layout is unchanged.

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

* feat(frontend): compact runs timeframe picker with a Start/End toggle on small screens

The two-calendar desktop popover needs ~780px (two min-w-9 grids + presets +
popover padding); below that it overflows. Under 800px, show a single calendar
with a Start/End toggle picking which bound it edits, using set-start/set-end so
each bound keeps its date and HH:MM time inputs — the same precision the desktop
start/end pair offers.

On short/landscape viewports the compact panel is scroll-contained within the
popover's fitViewport height (contentClasses overflow-y-auto, scoped to the
small layout) so its lower controls stay reachable. The desktop two-calendar
layout is unchanged.

Presets are shared between both layouts via a snippet, and the active range is
preserved across the breakpoint since both branches drive the same value.

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

* feat(frontend): let InlineCalendarInput month/year selects portal, use in compact timeframe picker

Add an opt-in `portalSelects` prop to InlineCalendarInput that portals the
month/year dropdowns to the body (default keeps them in-flow, so existing
consumers are unchanged). The compact runs timeframe picker enables it so the
dropdowns escape its scroll-contained (overflow-y-auto) popover instead of
being clipped.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:55:21 +02:00
Diego Imbert 2fe999f66c fix(frontend): treat a displaced draft save as superseded, not failed (#10094) 2026-07-15 17:55:01 +02:00
hugocasa 8bfe5c9340 fix(ai): stop sending the AI agent system prompt twice for OpenAI (#10126)
* fix(ai): stop sending the AI agent system prompt twice for OpenAI

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

* fix(ai): document collect_system_prompt precedence and trim duplicate comments

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

* fix(ai): hoist only the leading system prompt for OpenAI

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:53:09 +02:00
Ruben Fiszel 17872018cc feat(nsjail): make python/ansible rlimit_as configurable per worker (GIT-921) (#10138)
nsjail caps a jailed job's virtual address space at rlimit_as (4096 MiB for
python3 and ansible). JIT runtimes (Bun/JavaScriptCore, the JVM) reserve large
virtual ranges up front, so a subprocess spawned from a jailed Python/Ansible
job can crash against this cap even when its physical memory use is modest
(e.g. the Bun-compiled claude CLI hitting JSC/pthread allocation failures).

Most other language protos already run with disable_rl: true (unlimited);
python3 and ansible are the outliers with an explicit rlimit_as. This exposes
that cap via a per-language env var (NSJAIL_PY_RLIMIT_AS_MB,
NSJAIL_ANSIBLE_RLIMIT_AS_MB) so operators can raise or lift it on a dedicated
worker pool without a source patch/rebuild and without weakening the
mount/PID/user-namespace isolation that provides the real security boundary.
Only the address-space limit changes; cpu/fsize/nofile rlimits are untouched.

Value is in MiB, or unlimited/none/inf/0 to uncap (rlimit_as_type: INF). Unset
keeps the historical 4096 default.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:52:39 +02:00
Ruben Fiszel f7eb5c460d fix(apps): invalidate cached app policy on change or deletion (GHSA-r5v4-cxh9-7qhq) (#10121)
* fix(apps): invalidate cached app policy on change or deletion (GHSA-r5v4-cxh9-7qhq)

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

* docs(agents): keep PR tests and comments minimal and non-ephemeral

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:41:54 +02:00
hugocasa bd3adc9781 fix(frontend): only carry custom-tag overrides on 'Run again' (#10137)
* fix(frontend): only carry custom-tag overrides on 'Run again'

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(frontend): keep literal overrides on dynamic-tag reruns

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 17:33:42 +02:00
Ruben Fiszel 5626768471 fix(cli-image): patch fixable CRITICAL CVEs in windmill-cli image (GIT-922) (#10135)
The published ghcr.io/windmill-labs/windmill-cli image shipped two fixable
CRITICAL findings:

- openssl (libssl3t64, openssl-provider-legacy): stale in the oven/bun:slim
  base image (CVE-2026-34182). Fixed by running apt-get upgrade so the image
  picks up the patched Debian packages.
- vitest 2.1.9 (CVE-2026-47429 / GHSA-5xrq-8626-4rwp): a dev-only
  devDependency reference in esrap's cached package.json living in bun's
  package download cache. The cache is unused at runtime, so it is removed
  after install.

Validated by building the image and scanning with Trivy: openssl now reports
3.5.6-1~deb13u2 (fixed) and vitest is entirely absent. wmill still runs. The
only remaining CRITICALs are perl-base CVEs with no upstream fix available.

Fixes GIT-922

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:21:16 +02:00
Ruben Fiszel 188647a942 fix(security): enforce variables:write scope on resource-delete var cascade (GHSA-xmr2-98m6-cjf7) (#10123)
A token scoped only to resources:write:<path> could delete linked secret
variables it had no variables:write scope for, by embedding $var:<victim>
in an attacker-controlled resource value and triggering the resource-delete
cascade. #9712 re-enforced scoped-token boundaries broadly but missed this path.

Add check_linked_var_delete_scopes, called before the cascade in both
delete_resource and delete_resources_bulk: require variables:write for every
linked variable, failing (and rolling back) the delete otherwise. No-op for
unscoped tokens, so full-token cascade cleanup is unchanged.

No co-located-path exemption: a resource and a variable may share a path, and a
resource-write token can create a resource over an existing standalone variable
and self-reference it, so "same path as the deleted resource" is attacker-
forgeable and cannot stand in for variable scope.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 13:19:17 +02:00
Ruben Fiszel 6407d9ff5c fix(bash): normalize CRLF line endings before running scripts (#10131)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 12:46:26 +02:00
Ruben Fiszel 27ead8d084 fix(ai): disable redirects on worker AI provider client (GHSA-5q4v) (#10122)
* fix(ai): disable redirects on worker AI provider client (GHSA-5q4v)

The worker AI request path issued provider requests with the shared
HTTP_CLIENT, which follows up to 10 redirects without revalidating each
hop. SSRF validation on the provider base_url is single-shot, so a public
base_url could 3xx the worker into a private/internal host (e.g. cloud
metadata), bypassing the private-endpoint protection. The API proxy was
already hardened in #9370; the worker path was missed.

Add a dedicated AI_HTTP_CLIENT with redirects disabled and use it for the
user-controlled provider endpoint, mirroring the API proxy client.

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

* fix(ai): add ALLOW_AI_BASE_URL_REDIRECTS debug escape hatch

Off by default (redirects stay disabled). When set, restores redirect
following on the AI HTTP client for debugging non-standard/self-hosted
gateways, with a startup warning that it weakens SSRF protection.

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

* docs(ai): correct redirect comment for the escape hatch override

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

* docs(ai): condense redirect invariant comments per review

Anchor the SSRF rationale to ALLOW_AI_BASE_URL_REDIRECTS (the knob that
would break it) and shorten the AI_HTTP_CLIENT and call-site comments to
avoid restating it at multiple sites (AGENTS.md).

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:24:26 +02:00
Ruben Fiszel 73c8d7f08a fix: reject git URL fragment/query SSRF bypass (GHSA-p5cj-8cfh-mjv6) (#10120)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:07:04 +02:00
Ruben Fiszel 360e783b1d chore(main): release 1.759.0 (#10108)
* chore(main): release 1.759.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.759.0
2026-07-15 10:02:01 +02:00
hugocasa ebe31aeeac feat(dev-workspace): reflect existing protection rules in lock toggles (#10093)
* feat(dev-workspace): reflect existing protection rules in lock toggles

When creating or attaching a dev workspace, the "block direct edits" and
"prevent forking" toggles now check the root workspace's current protection
rules. If a restriction is already enforced by an existing rule, its toggle is
shown on but locked, with a note, instead of offering a fresh default that could
misrepresent the effect. The value sent to the backend is derived so it stays
consistent with what the locked toggle shows.

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

* docs: clarify fail-open comment on dev-workspace lock toggles

Reword the protection-rule fetch comment so the fallback path isn't misread as
dropping protection: a failed fetch falls back to the editable default-on
toggle, and any real rule still enforces server-side.

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

* fix(dev-workspace): lock protection toggles until rules load

The lock toggles derived alreadyBlocks* from an async fetch, so during the load
window (and the first frame before loading flips) they were editable and the
effective value could be false. A user could turn a lock off and submit before
an existing rule was detected, omitting the reserved rule and silently leaving
prod unprotected once that existing rule was later removed.

Treat "rules not yet known" (loading || current === undefined) the same as
"already enforced": lock the toggle on and keep the effective value true during
that window, so the request can never submit false before the fetch resolves.
Submission stays available (a hung fetch degrades to over-protection, not a
blocked form). Also fixes the stale-value flash when switching base workspace.

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

* fix(dev-workspace): honor rule bypasses and guard stale protection fetches

Two issues in the protection-rule awareness for the dev-workspace lock toggles:

- Bypassable rules became unconditional locks. alreadyBlocks* used
  isRuleActiveInRulesets, which ignores bypass_users/bypass_groups, and forced
  the request flag to true. The reserved dev_workspace_lock rule is created with
  empty bypass lists, so layering it over an existing rule that let specific
  users through revoked their deploy/forking access. Switch to
  isRuleUnconditionallyActiveInRulesets so a toggle is only shown as already
  enforced (locked) when an existing rule has no bypasses; a bypassable rule
  stays editable, making the lock the user's explicit choice.

- A stale protection fetch could apply another base's rules. The generated
  client can't take an abort signal, so a delayed response for a previous base
  could overwrite the newly selected one. Tag each result with its workspace and
  only trust a result matching the current base; also throw AbortError from a
  superseded fetch so it can't overwrite current.

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

* docs: condense protection helper comment to four lines

Trim the isRuleUnconditionallyActiveInRulesets doc comment to satisfy the
AGENTS.md ≤4-line comment rule.

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

* fix(dev-workspace): align already-enforced note under the toggle label

The note used ml-8, landing under the toggle switch rather than aligned with
the switch edge or the label, so it read as floating. Bump to ml-11 so it lines
up under the label as helper text for that toggle.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 10:01:35 +02:00
Ruben Fiszel cab3430e64 ci: link backend integration tests with mold to fix OOM (exit 143) (#10103)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 10:00:50 +02:00
Kobi Hikri 91b5a10504 ci: pin cpina/github-action-push-to-another-repository to a full commit SHA (#10119)
go_on_release.yml referenced this third-party action by the mutable @devel
branch in the step that holds secrets.DENO_PAT (a write-scoped PAT used to push
the generated go-client to another repo). Pinning to a full commit SHA (v1.7.3)
removes the mutable-ref supply-chain exposure, consistent with the other
SHA-pinned actions in the repo.
2026-07-15 09:52:50 +02:00
Ruben Fiszel eb7a2e048b ci: cap build jobs and disable incremental in backend tests to prevent OOM (#10118) 2026-07-15 09:50:16 +02:00
Ruben Fiszel 6d1e12d5e9 feat(nativets): expose the standard web-platform globals deno_web provides (#10112)
* feat(nativets): expose standard web-platform globals for bun parity

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

* feat(nativets): wire bun-present Event subclasses and add construction smoke test

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

* fix(nativets): seed performance.timeOrigin per isolate, drop broken reportError

Addresses CI Codex review on #10112:
- performance.timeOrigin was undefined (setTimeOrigin never called); seed it
  per isolate via __wmInitPerIsolate executed from create_nativets_runtime.
- reportError needs a global EventTarget this runtime never installs; drop it.
- reword the namespace-import comment to not describe drafting history.

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

* feat(nativets): wire DOMException global + broad edge-case smoke sweep

DOMException is present in bun and, more importantly, deno_web references it as
a global: AbortController.abort() with no reason constructs a
DOMException("...", "AbortError"), so the already-wired AbortController/
AbortSignal threw "DOMException is not defined" on abort. Surfaced by a new
functional edge-case sweep (smoke_web_globals_edge_cases) that exercises every
wired global for real (not just presence) — DOMException/abort, AbortSignal.timeout,
EventTarget dispatch, stream tee/reader/writer, all 3 compression formats,
structuredClone Map/Set/Date/circular/reject-function, performance mark/measure,
MessagePort delivery — plus a check that the merged Web Crypto globals still work.

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

* test(nativets): restore arg-default smoke tests dropped in merge, drop history comments

Addresses CI Codex/Pi review on the merge commit:
- Merge conflict resolution (checkout --ours) dropped smoke_missing_optional_arg_uses_default
  and smoke_explicit_null_arg_is_preserved (added on main by #10111); restore them.
- Reword edge-case-sweep comments to state the constraint, not how the gaps were found.

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

* fix(nativets): give reportException a global dispatch target; wire stream reader/controller globals

Addresses CI Codex review on #10112:
- P1: a throwing EventTarget listener (and reportError) is routed through
  deno_web's reportException, which dispatches on a saved global reference.
  With none set, dispatchEvent threw a masking error that hid the original.
  Wire a dedicated EventTarget as that target so the ORIGINAL error is reported
  (async unhandled, matching bun). Does NOT make globalThis an EventTarget (bun's
  isn't either). Re-adds reportError, now functional. Regression test asserts the
  original error is surfaced, not a masking one.
- P2: wire the stream reader/controller globals bun also exposes
  (ReadableStreamDefaultReader/BYOBReader, ReadableStreamDefault/ByteStreamController,
  ReadableStreamBYOBRequest, WritableStreamDefaultWriter/Controller,
  TransformStreamDefaultController) for instanceof parity; sweep verifies via real
  reader/writer/controller instances.

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

* fix(nativets): make globalThis an EventTarget so globalThis.reportError() works

Addresses follow-up CI Codex review on #10112:
- P1: the prior fix saved a *separate* EventTarget as the global reference, so
  globalThis.reportError() still failed its receiver check (this === globalThis_)
  with 'Illegal invocation'. Make globalThis itself the saved reference by turning
  it into a functional EventTarget (setPrototypeOf to DedicatedWorkerGlobalScope +
  setEventTargetData + webidl brand + saveGlobalThisReference), per isolate in
  __wmInitPerIsolate. Both reportError(e) and globalThis.reportError(e) now surface
  the original error (async, matching bun) instead of throwing. New test
  smoke_report_error_both_call_forms covers both call forms.
- P2: reword the regression-test comment to state the invariant, not the patch history.

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

* feat(nativets): wire performance constructor globals for bun parity

Addresses the P2 nit in the CI Codex review: bun exposes Performance,
PerformanceEntry, PerformanceMark, and PerformanceMeasure as globals (deno_web
exports all four), so wire them alongside the performance singleton. The
edge-case sweep verifies instanceof against real mark/measure entries.

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

* docs(nativets): state global-wiring comment as a constraint, not patch history

Addresses the P2 in the CI Codex review: reword the block comment to describe
the current bun-parity constraint and the deliberate EventSource/ImageData
exclusions, without narrating what was or wasn't wired before (per AGENTS.md).

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 09:47:54 +02:00
Ruben Fiszel 95d9ff02ee fix(jseval): raise QuickJS eval memory cap to 128MB with clear OOM error (#10116)
* fix(jseval): raise QuickJS eval memory cap to 128MB with clear OOM error

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

* docs(jseval): note bare null/undefined throws are absorbed into OOM bucket

Addresses CI review P2 nit on map_quickjs_error.

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

* fix(jseval): keep batch-rerun eval on a conservative 32MB cap; tighten OOM match

Addresses CI review: eval_simple_js runs in the API process with unbounded request concurrency, so it must not inherit the raised flow-transform cap. Tighten the Exception OOM match to exact string. Reword drafting-history comments per AGENTS.md.

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

* fix(jseval): gate OOM on InternalError kind; path-specific remediation hint

Require the OOM InternalError name (not just the message) so a user throw new Error('out of memory') is not misclassified, and only suggest QUICKJS_MEMORY_LIMIT_MB on the env-tunable flow path (not the fixed-cap eval_simple_js path).

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 09:35:55 +02:00
Ruben Fiszel a6191e2a85 fix(mcp): advertise flow input variables in MCP tools (#10117)
Flow input schemas omit `required` (they carry an `order` key instead),
which made `serde_json::from_str::<SchemaType>` fail in
`convert_schema_to_schema_type`. The error was swallowed and callers fell
back to an empty `SchemaType::default()`, so MCP flow tools advertised no
inputs. Add `#[serde(default)]` to `type`, `properties`, and `required` on
`SchemaType` so these schemas deserialize correctly. Scripts always include
`required` and were unaffected.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 09:04:50 +02:00
Ruben Fiszel e9fd4e7554 perf(rls): wrap session GUC reads in RLS policies for per-statement InitPlan (GIT-919) (#10110)
* perf(rls): wrap session GUC reads in RLS policies for per-statement InitPlan

RLS policies read current_setting('session.user' / 'session.groups' /
'session.pgroups' / 'session.folders_read' / 'session.folders_write')
directly inside their USING / WITH CHECK predicates. Postgres treats those
unwrapped calls as potentially row-varying and re-evaluates them once per
scanned row, on the read path of every workspace-scoped table.

The GUCs are set with SET LOCAL (set_config(..., true)) in
set_session_context(), so they are constant for the duration of a statement.
Wrapping each session-derived subexpression in a scalar sub-select lets the
planner hoist it to a one-time InitPlan (evaluated once per statement, reused
for every row) — same rows in, same rows out, N per-row GUC lookups collapse
to 1. Array-producing subexpressions keep an explicit ::text[] cast on the
sub-select so `= ANY (...)` / `?|` stay in their array-operand form rather
than being reparsed as a row-returning subquery.

The consolidating migration recreates every existing policy (across ~30 prior
migrations) whose predicate reads a session GUC, by deparsing the current
predicate and substituting the wrapped forms; the down migration is the exact
inverse (byte-identical round-trip). The adding-a-trigger skill documents the
wrapped form so new trigger tables inherit it.

Surfaced by pgrls (PERF001).

Fixes GIT-919

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

* docs(adding-a-trigger): fix RLS example cast placement for = any context

The `= any(...)` example put the ::text[] cast inside the sub-select, which
Postgres parses as a row-returning subquery and rejects at CREATE POLICY with
`operator does not exist: text = text[]`. Move the cast outside the sub-select
(matching the migration's canonical form) so the operand stays in array form,
and note why.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 08:56:05 +02:00
Ruben Fiszel 88030d0f55 fix(tree-view): align file indentation with sibling folders (#10115)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 02:03:47 +02:00
Ruben Fiszel ba232544e7 feat(nativets): add Web Crypto support via deno_crypto (#10109)
The nativets in-process runtime (deno_core) exposed no Web Crypto API:
`crypto` was undefined, so scripts could not use `crypto.getRandomValues`,
`crypto.randomUUID`, or `crypto.subtle`, even though the bun runner provides
them. This closes that parity gap by registering the `deno_crypto` extension
and wiring the crypto globals onto `globalThis`.

- Pin `deno_crypto = "0.223.0"`, the sibling release of the already-pinned
  deno_core 0.352 / deno_web 0.240 stack (deps: deno_core ^0.352,
  deno_web ^0.240, deno_error =0.6.1), so the rest of the deno stack is
  untouched.
- Register `deno_crypto::init(None)` after `deno_web` in both the snapshot
  (build.rs) and the runtime (lib.rs) extension lists, keeping the snapshot a
  prefix of the runtime list. deno_crypto declares deps = [deno_webidl,
  deno_web], which the position satisfies.
- Import `ext:deno_crypto/00_crypto.js` in runtime.js and assign
  `crypto` / `Crypto` / `CryptoKey` / `SubtleCrypto` to `globalThis`.
- Add the `smoke_web_crypto` opt-in smoke test asserting the UUIDv4 shape of
  `randomUUID`, a non-zero `getRandomValues` fill, and the known
  SHA-256("abc") vector via `subtle.digest`.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 01:58:56 +02:00
Ruben Fiszel 4917f79935 fix(mcp): let MCP tokens call preview run tools (jobs:run scope) — Fixes GIT-920 (#10107)
* fix(mcp): let MCP tokens call preview run tools (jobs:run scope)

The MCP proxy mints an internal JWT scoped to exactly `scope_for_route`
for the endpoint it forwards to. For preview run routes
(`run/preview`, `run/preview_bundle`, `run/preview_flow`,
`run_wait_result/preview`, `run_wait_result/preview_flow`),
`determine_kind_from_route` matched the `SCRIPT_JOBS` prefix
`jobs/run_wait_result/p` (because "preview" starts with "p") and derived
`jobs:run:scripts`. But the preview handlers run arbitrary request-supplied
code with no deployed path and require the broad `jobs:run` scope, so
`jobs:run:scripts` was rejected with 403 "Required scope: jobs:run".

Preview/bundle routes now carry no runnable kind, so the derived scope is
the broad `jobs:run` the handlers expect. This also aligns the route-level
access check with the handler check for these routes.

Fixes GIT-920

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

* fix(mcp): anchor preview-route match to endpoint segment

Address CI review: `route_path.contains("preview")` also matched by-path
runs of a deployed runnable whose path contains "preview" (e.g.
`jobs/run_wait_result/p/f/team/preview_report`). Since determine_kind_from_route
also feeds check_route_access, such a route would derive the broad `jobs:run`
and reject a legitimately kind-scoped `jobs:run:scripts:*`/`jobs:run:flows:*`
token with 403.

Anchor the exception to the actual preview endpoints
(`jobs/run/preview*`, `jobs/run_wait_result/preview*`) so by-path runs keep
their kind. Add regression tests for preview-named by-path paths, and trim
the comments per AGENTS.md.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 01:56:41 +02:00
Ruben Fiszel ba7f9c065f fix(nativets): apply parameter defaults for missing args instead of null (#10111)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 01:53:43 +02:00
Ruben Fiszel abbab4d423 security(docker): apt-get upgrade base OS in all runtime base stages (#10114)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 01:50:50 +02:00