Commit Graph

3372 Commits

Author SHA1 Message Date
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>
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>
2026-07-15 18:00:53 +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
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>
2026-07-15 10:02:01 +02:00
Ruben Fiszel 65d6f477ab chore(main): release 1.758.0 (#10084)
* chore(main): release 1.758.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-14 22:38:45 +02:00
hugocasa 4edffeb84b fix(mcp): align script auto_kind filter with scripts list API (#10098)
The MCP `get_items` script filter used `auto_kind IS NULL`, which excluded
every script with a non-null `auto_kind` (pipeline, test, WAC, ...). These
are valid runnable scripts and should surface as MCP tools.

Switch to the deny-list `(auto_kind IS NULL OR auto_kind <> 'lib')`, matching
the scripts list API (windmill-api-scripts). Only library scripts (no main
function) are excluded; pipeline/test/WAC and any future auto_kind values are
included.

Fixes WIN-2190

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:00:27 +02:00
Ruben Fiszel 1ffe5a1075 chore(main): release 1.757.0 (#10080)
* chore(main): release 1.757.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-14 12:47:53 +02:00
Ruben Fiszel 4f65187f9e chore(main): release 1.756.1 (#10072)
* chore(main): release 1.756.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-14 10:46:55 +02:00
Ruben Fiszel 710a13a59d fix(apps): cover script/flow component outputs in deployed-app S3 provenance gate (#10070)
* fix(apps): cover script/flow component outputs in deployed-app S3 provenance gate

Deployed apps read S3 files on-behalf of the app author for logged-in viewers
(#10048). A confused-deputy guard confines those reads to files the app
"produced", but the recent-production check only matched inline `appscript`/
`preview` jobs nested under the app path. Files produced by the deployed
script/flow components an app is wired to run (e.g. a SQL query persisted to S3)
were therefore denied "File restricted" for every viewer, admins included.

Expand the provenance check to also match completed `script`/`flow`/`flowscript`/
`flownode` jobs whose `runnable_path` is one of the app's declared triggerables,
and accept the author identity via `permissioned_as = on_behalf_of` (not only
`created_by = caller`) so files produced on-behalf of the author are covered.
Reads outside the app's declared triggerables stay denied.

Adds a regression test seeding a script-kind produced file that reproduces the
"File restricted" denial before the fix and passes after.

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

* fix(apps): key S3 provenance on on-behalf identity + cover flow steps (review)

Addresses the CI review on the S3 provenance gate:

- P1 (confused deputy): the recent-production check keyed on `created_by =
  caller`, so a viewer who can run a declared script/flow directly (outside the
  app, with un-pinned inputs) could craft a result naming an author-only key and
  read it back through the app as the author. Key provenance instead on the
  producing job's `permissioned_as` matching the on-behalf identity the download
  reads as (the author in author-mode); a viewer's direct run has
  `permissioned_as = viewer` and no longer clears the gate. Drops `created_by`
  from both the appscript/preview and script/flow branches, closing the same
  latent hole in the pre-existing inline-script branch.

- P2 (dead flow-step branch): `flowscript`/`flownode` jobs have
  `runnable_path = <flow_path>/<step_id>`, which exact `= ANY(...)` never matched.
  Split script vs flow triggerable paths; flow kinds now match the flow's own job
  (bare path) and its step jobs via a `<flow_path>/%` prefix, bounded to declared
  flows.

- P2 (test realism): the regression test now uses the production
  component-prefixed triggerable key format (`<id>:script/...`), exercises a
  flow-step-produced key, and asserts a viewer's own direct run of a declared
  script stays denied (the P1 case).

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

* fix(apps): tie deployed-app S3 provenance to an app-origination marker (review)

Second CI-review round flagged that `permissioned_as` still does not prove a job
was app-launched: a runnable configured with its own `on_behalf_of` makes a direct
`/jobs/run` resolve `permissioned_as` to that identity (the app author), so a viewer
with run access could execute a declared runnable directly, craft an S3 result, and
read it back through the app. The flow-path `LIKE fp || '/%'` match also let `_`/`%`
in a declared path admit unrelated flows.

Introduce a real app-origination marker instead of inferring provenance:

- Add `JobTriggerKind::App`; `execute_component` stamps every app-launched job with
  `trigger_kind = 'app'` + `trigger = <app path>`. A direct `/jobs/run` cannot set
  this, so it is the authoritative signal that a file was produced *by the app*.
- The provenance gate's recent-production check collapses to
  `trigger_kind = 'app' AND trigger = <this app path>` (+ the 3h window and result
  containment). This drops the forgeable `created_by`/`permissioned_as`/
  `runnable_path`/kind logic entirely and removes the `LIKE` wildcard issue.
- Provenance is scoped to THIS app's path, so another app's jobs (even same author)
  do not authorize this app's reads.

Regression test rewritten to the marker model: an app-produced key clears for viewer
and admin; a direct run whose `permissioned_as` resolves to the author stays denied
(the forgery); another app's output stays denied. Adds `app` to the OpenAPI
JobTriggerKind enum.

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

* test(apps): assert execute_component stamps trigger_kind='app' at runtime

Adds an end-to-end test that runs a real script component through the app
runtime (`apps_u/execute_component`) and asserts the enqueued job carries the
app-origination marker `trigger_kind = 'app'` + `trigger = <app path>` (not the
runnable path). The provenance-gate tests seed the marker directly; this proves
the runtime actually produces the exact marker the gate depends on.

execute_component commits the job row and returns its id, so the assertion reads
the row directly — no worker needed to run the job.

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

* fix(triggers): reject trigger_kind=app for suspended-job reassignment (review)

`JobTriggerKind::App` (added for the app-origination S3 marker) became a valid
value for the resume/cancel suspended-trigger routes, whose handler derives the
table name `<kind>_trigger`. There is no `app_trigger` table, so both endpoints
would fail with a missing-relation database error (500). Reject `App` in
`get_suspended_trigger` alongside webhook/schedule so it returns a clean 400.

Adds a regression test asserting the reassignment route returns 400 (not 500) for
trigger_kind=app.

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

* fix(apps): don't stamp app-origination marker on preview runs (review)

The app-origination marker (trigger_kind='app') was stamped unconditionally,
including preview mode. A preview lets a `jobs:run` caller supply arbitrary
`raw_code` against ANY app path without that app's deployed policy (raw_code with
no path/id skips all app authorization), so a preview returning
`{"s3":"<author-only-key>"}` would forge the exact marker the S3 provenance gate
trusts and read the victim app author's file.

Gate the marker on `!is_preview`: only deployed, policy-checked executions are
app-provenanced. Preview/editor S3 display does not rely on this marker (the editor
routes reads through the force_viewer allowlist), so nothing legitimate regresses.

Adds a regression test asserting a preview run's job is not stamped trigger_kind='app'.

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

* fix(apps): editor-authorize preview marker + per-viewer S3 provenance isolation (review)

Closes the codex P1 (preview forgery) without breaking editor preview downloads,
and adds cross-viewer isolation to the provenance gate.

- Preview marker now requires app write: `execute_component` stamps the
  app-origination marker on a preview only when the caller can EDIT that app
  (`require_is_writer`), instead of never stamping previews. An app editor already
  wields the app's author identity (they can deploy a component that reads the same
  file), so marking their own preview is no escalation and keeps preview-produced
  S3 results downloadable in the editor; a `jobs:run`-only caller who cannot edit
  the app still cannot forge the marker. Deployed runs are unchanged (always
  marked).

- Per-viewer isolation: the provenance gate now also requires
  `j.created_by = <this caller>`. The security boundary stays the un-forgeable
  `trigger_kind='app'` marker; `created_by` is an additional filter ANDed under it,
  so it only narrows — a viewer can only download keys their OWN app runs produced,
  not another viewer's result. Restores the per-caller scoping #10048 had, now safe
  on top of the marker.

Tests: preview marked iff caller can edit the app; cross-viewer isolation (another
viewer's app-marked key denied, no admin bypass); direct-run and other-app keys
still denied; deployed run still stamped.

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

* fix(apps): require apps:write scope (not just writer ACL) to mark preview provenance (review)

require_is_writer checks the user's underlying ACL but ignores token scopes, so a
writer's token deliberately scoped to apps:run/apps:read/jobs:run but WITHOUT
apps:write could still mark a preview and forge provenance — even though that token
cannot deploy the app (update_app requires apps:write), breaking the "any marked
caller can deploy equivalent code" rationale.

Require BOTH apps:write:<path> scope (check_scopes) AND the writer ACL
(require_is_writer) before stamping a preview's app-origination marker. Deployed
runs unchanged.

Adds a scope-restricted-writer token to the test (apps:run/read + jobs:run, no
apps:write) and asserts its preview stays unmarked; retains the full-editor
positive case and the non-editor negative case.

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

* fix(apps): never app-provenance preview runs; read editor S3 as the caller (review)

Simplifies the preview handling: a preview executes as the *caller* (Viewer mode),
never as the author, so its results must be read back as the caller — never
author-mode — and must never carry the app-origination marker. This removes the
whole `require_is_writer` / `apps:write` / `can_preserve_on_behalf_of` reasoning
(which was also unsound: a writer's token or session may not be able to deploy a
component running as the app's on-behalf identity, so marking their preview could
still escalate).

- Backend: mark the app-origination marker for deployed runs only (`!is_preview`).
- Frontend: `getS3File` (AppImage/AppPdf/AppDownload) now routes editor/preview
  reads through the viewer-scoped `job_helpers/download_s3_file` endpoint (reads as
  the caller), matching what DisplayResult/ParqetCsvTableRenderer already do; only
  a deployed app view uses the provenance-gated `apps_u` endpoint. This is the path
  that previously relied on marking previews, so nothing regresses.

Test: a preview is never app-provenanced (owner's own preview and a non-editor's
both stay unmarked). Cross-viewer isolation, deployed marking, and the reassignment
guard are unchanged.

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

* fix(apps): app components run on-behalf of the app, not the referenced runnable (review)

Root-causes codex's on-behalf-preview finding: `execute_component` was overriding the
app's resolved on-behalf identity with the referenced script/flow's OWN
`on_behalf_of` (its `on_behalf_of_email`). That is wrong in the app context — the
app's execution mode should govern:

- A Viewer-mode app could execute a component AS the referenced runnable's on_behalf
  identity (privilege confusion / escalation), instead of as the viewer.
- A preview would run as that identity rather than as the caller, so its S3 output
  could not be read back as the caller — the download-identity mismatch codex flagged.

Always use the app-resolved identity (author in author-mode, caller in
viewer/preview); a referenced runnable's own `on_behalf_of` no longer leaks into app
execution. Direct `/jobs/run` still honors a runnable's `on_behalf_of` (unchanged).
With this, previews always run as the caller, so reading editor/preview S3 as the
caller (viewer-scoped `job_helpers`) is unconditionally correct.

- Test: the deployed-component e2e now seeds the script with a distinct on_behalf and
  asserts the component job's `permissioned_as` is the app identity, not the script's.
- Also reword the getS3File `configuration` param comment to describe current state
  only (AGENTS.md comment rule).

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

* chore(apps): surface 'app' trigger kind in Runs UI; condense provenance comments (review)

Addresses codex review nits:
- Add `app` to `jobTriggerKinds`, `triggerIconMap` (LayoutDashboard), and
  `triggerDisplayNamesMap` so app-component jobs (which now carry
  `trigger_kind = 'app'`) are filterable in Runs and render their trigger info.
- Condense the app-origination marker, on-behalf-identity, and provenance-gate
  comments to state each invariant once in <=4 lines at its relevant site
  (AGENTS.md comment rule).

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-14 10:29:48 +02:00
Ruben Fiszel 22b47c8823 chore(main): release 1.756.0 (#10062)
* chore(main): release 1.756.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-12 10:30:58 +02:00
Ruben Fiszel 1ed7fc066b chore(main): release 1.755.0 (#10041)
* chore(main): release 1.755.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-12 00:01:39 +02:00
Ruben Fiszel ff774c46bf feat: add per-workspace job-retention override (#10050)
* feat: add per-workspace job-retention override (EE)

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

* chore: update ee-repo-ref to 2ba6a2a75b6fc97858b306b2c98ada481e363c10

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

Previous ee-repo-ref: e7fb36acd813cd717bcf05f5aafbf81de271d618

New ee-repo-ref: 2ba6a2a75b6fc97858b306b2c98ada481e363c10

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-11 23:46:34 +02:00
Ruben Fiszel 04eb7ddd39 fix: clearer errors on auto-draft save failure (WIN-2157) (#10053)
* fix: clearer errors on auto-draft save failure (WIN-2157)

When an autosave draft save fails, the cloud indicator now surfaces the
backend reason on hover (native title tooltip) in addition to the
existing click popover, so the cause is discoverable without a click.

Backend now returns a clearer, actionable message:
- `require_can_write_path` distinguishes a malformed path (unrecognized
  namespace prefix -> BadRequest) from a genuine permission denial, and
  the deny message spells out where the user *can* write.
- `require_owner_of_path` no longer panics with an out-of-bounds index on
  a malformed single-segment path (e.g. a bare `u`/`f`); it returns a
  clear BadRequest instead. Covered by a regression test.

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

* chore: trim narrative comment to invariant in drafts.rs (WIN-2157)

Address CI review (AGENTS.md: comments record constraints, not narration,
≤4 lines): keep the malformed-path invariant, drop the motivation tail.

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

* fix: don't let a malformed stored draft 400 the draft listing (WIN-2157)

Address CI review (P1): require_can_write_path can now return BadRequest
for a malformed path, and list_drafts propagated it — so a single
malformed stored draft row (the draft table has no path constraint;
legacy/admin-authored rows may be malformed) would make GET /drafts/list
return 400. Treat BadRequest like NotAuthorized there: the row is simply
not writable. Verified e2e on EE — listing returns 200 with can_write
false for the malformed rows.

Also trim "unchanged"/"still" drafting-history narration from the
regression test comments (P2, AGENTS.md).

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

* chore: compress list_drafts comment to 4 lines (WIN-2157)

Address CI review P2: keep the constraint (draft table has no path
constraint) and the invariant (one malformed row must not 400 the
listing) within the AGENTS.md ≤4-line limit.

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-11 16:00:53 +02:00
Ruben Fiszel 1e192f2d86 feat(apps): authorize deployed-app S3 reads on-behalf of the author for logged-in viewers (#10048)
* feat(apps): authorize deployed-app S3 reads on-behalf of the author for logged-in viewers

A logged-in user viewing a deployed app now reads S3 files (rich result,
table/image/PDF preview, CSV export, download, metadata) the same way an
anonymous viewer already does: on-behalf of the app author per the app policy's
execution_mode, gated by an app-provenance check — instead of against the
viewer's own S3 permissions. This aligns S3 with every other thing an app does
(scripts, flows, resources all already run on-behalf of the author) and lets an
operator who lacks folder S3 permission still see data rendered inside the app.

The raw job_helpers/* S3 API stays viewer-scoped: a viewer who lacks folder
permission is still denied there. Only which endpoint the app frontend uses for
logged-in deployed viewers changes.

Backend:
- Add app-scoped, provenance-gated apps_u/* variants for all S3 display ops
  (download_s3_file already existed; add download_s3_parquet_file_as_csv,
  load_file_metadata, load_file_preview, load_parquet_preview, load_csv_preview,
  load_table_count). Each routes through one shared helper
  (app_s3_on_behalf_and_provenance) that scope-confines an app embed token,
  resolves the on-behalf identity, and runs the provenance gate ONCE before
  dispatching to the EE *_internal S3 helpers.
- Close the confused-deputy hole in check_if_allowed_to_access_s3_file_from_app:
  the unconditional Ok() bypass for a logged-in, non-embed session now only
  applies in viewer execution mode (where the on-behalf identity IS the viewer,
  so the viewer's own permissions still bound the read downstream). Author-mode
  reads (anonymous/publisher) always enforce provenance, for anonymous and
  logged-in viewers alike, so a viewer cannot launder the author's S3
  permissions with an arbitrary file_key.

Frontend:
- Route the deployed-app view through apps_u/* using the app-viewer isEditor
  signal instead of login state (the old $userStore proxy wrongly sent
  logged-in deployed viewers to the viewer-scoped job_helpers API). Editor and
  preview keep viewer identity via job_helpers.

execution_mode: viewer remains the escape hatch for per-viewer S3 enforcement.

Fixes provenance-gated S3 display for logged-in operators on deployed apps.

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

* docs(backend): document cargo features, restarting the dev backend, and filesystem object storage

The dev backend runs `cargo watch --features quickjs` by default, which omits S3,
EE, MCP, and non-JS runtimes — feature-gated routes then 404 or return a
"requires <feature>" stub at runtime. Add a backend/CLAUDE.md section that:

- explains that you must restart the backend with the appropriate features to
  exercise gated functionality, with the pid/cwd-scoped restart recipe (never
  pkill target/debug/windmill) and the PORT=$BACKEND_PORT gotcha;
- documents what each commonly-toggled feature gate does (private, enterprise,
  license, parquet, duckdb, language runtimes, mcp, trigger kinds, no_auth) plus
  common combinations;
- documents using the built-in FilesystemStorage large-file storage for dev
  workspace object storage (hidden from the UI dropdown; set via
  edit_large_file_storage_config), including the advanced_permissions shape.

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

* fix(apps): don't flatten inner query in app-scoped S3 preview routes

axum's `Query` uses `serde_urlencoded`, which cannot deserialize the typed
(numeric/bool) fields of a `#[serde(flatten)]`-ed struct and 400s on `limit` /
`offset` ("invalid type: string, expected u32"). The app-scoped
load_csv_preview / load_parquet_preview / load_table_count routes flattened
LoadPreviewQuery / LoadCountQuery, so their previews were broken. Restate the
fields directly on the outer query structs (with an into_inner() to rebuild the
inner query) and extend the CE OSS stub to match.

Also bumps ee-repo-ref.txt for the companion EE csv-separator panic fix.

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

* fix: address CI review — nested DisplayResult routing, byte-range contract, docs, tests

- [P1] Thread `appPath` into the nested `DisplayResult`s (render_all children and
  the expanded-result drawer) so logged-in deployed viewers route nested/expanded
  S3 tables, images, PDFs, and downloads through `apps_u/*` too, not job_helpers.
- [P2] Mark `read_bytes_from`/`read_bytes_length` required on the
  `apps_u/load_file_preview` route (they are non-optional in LoadFilePreviewQuery),
  and mirror the full query shape in the CE OSS stub so the byte-range contract is
  enforced identically on CE and EE.
- [P2] Fix the backend retrigger command in backend/CLAUDE.md: cargo watch runs
  from `backend/`, so `touch README.md` (not `backend/README.md`).
- [P2] Trim app_s3_onbehalf.rs comments per AGENTS.md (state the invariant once,
  no drafting-history narration).
- Extend the integration test to cover the table-count, csv-preview (numeric
  limit/offset deserialization), and file-preview (byte-range required) routes.

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

* docs(apps): tighten S3 provenance-gate comments per AGENTS.md

Consolidate the viewer-mode / author-mode rationale to ≤4 lines at each branch
of the gate, and drop the repeated explanation from the shared
app_s3_on_behalf_and_provenance doc comment (which now just states what the
helper does). No behavior change.

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

* chore: update ee-repo-ref to f292a1040da6a667ce7c22abf63ec0debfdd480f

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

Previous ee-repo-ref: a582389084eb363997cb5e8053f29220e0d3eaec

New ee-repo-ref: f292a1040da6a667ce7c22abf63ec0debfdd480f

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-11 10:14:40 +02:00
Ruben Fiszel 5844c32ac5 fix: enforce read authorization when signing S3 objects (#10049)
`sign_s3_objects` minted a long-lived HMAC bearer signature for any S3 key
handed to it, by any authenticated workspace member, with no check that the
caller was allowed to read that key. Since `validate_s3_signature` only
verifies the HMAC and expiry at fetch time, any member (operators included)
could mint a transferable capability to read arbitrary S3 keys, bypassing the
advanced S3 permission rules (`check_lfs_object_path_permissions`).

Authorize the read at mint time: add an `ApiAuthed` extractor and, before
signing each key, require the caller's own `S3Permission::READ` via
`get_workspace_s3_resource_and_check_paths`. A caller can no longer sign a key
they cannot themselves read. The fetch-side validators are left unchanged.

The only legitimate caller is the wmill SDK invoked from an app-author job,
whose token authenticates as the executing (author) identity — which can read
the key — so authorized app display is unaffected.

Adds an integration test proving an authorized caller can sign a readable key
(and the signature validates end-to-end through the presigned fetch route)
while an unauthorized caller is refused.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 05:57:48 +02:00
Ruben Fiszel 8343203ec2 feat(mcp): add multi-workspace MCP tokens via the gateway endpoint (#10043)
* feat(mcp): add multi-workspace MCP tokens via the gateway endpoint

A single MCP token with no bound workspace (workspace_id NULL + mcp scope)
now works across every workspace the token owner can access, served through
the existing /api/mcp/gateway endpoint. This avoids having to register one
MCP server entry per workspace in clients like Claude/Cursor.

In multi-workspace mode the runner exposes a synthetic `list_workspaces`
tool plus the generic API endpoint tools, each workspace-scoped one gaining
a required `workspace_id` argument (mirroring the proxy pattern users built
externally). Per-workspace scripts/flows are not enumerated to avoid
flooding the tool list — they are run via runScriptByPath/runFlowByPath
with an explicit workspace_id.

Auth is resolved per tool call: the gateway middleware detects a
workspace-less mcp token and marks the request MultiWorkspaceMcp, and the
runner resolves a per-workspace ApiAuthed from the raw token via the
AuthCache (validating membership; superadmins may act in any workspace).
Single-workspace tokens are unchanged.

Frontend: the MCP token creation flow gains an "All workspaces" option that
produces a workspace-less token and the gateway URL.

Fixes WIN-2153

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

* test(mcp): cover multi-workspace endpoint tool transformation

Unit tests for endpoint_tool_to_mcp_tool_multi and list_workspaces_tool:
workspace-scoped tools gain a required workspace_id arg, global tools are
left unchanged, workspace_id is not duplicated, and list_workspaces takes
no arguments.

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

* fix(mcp): forward script/flow args for runScriptByPath/runFlowByPath

These endpoints have an additionalProperties body (no declared properties),
so build_request_body previously returned an empty body and dropped every
script/flow argument. This was latent for the per-path run endpoints and
became load-bearing in multi-workspace mode, where scripts/flows can only be
run via runScriptByPath/runFlowByPath — parameterized runs silently lost
their arguments.

build_request_body now forwards all arguments not consumed by a path/query
parameter for pass-through (additionalProperties) bodies, keeping the strict
declared-only behavior for endpoints with explicit properties. The runner
strips the synthetic workspace_id argument before dispatch so it can't leak
into the forwarded body.

Reported by Codex review on #10043.

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

* feat(mcp): note workspace_id requirement in multi-workspace tool descriptions

Workspace-scoped tools already gain a required workspace_id parameter (with
its own schema description) in multi-workspace mode, but the tool's prose
description was unchanged. Append a note so models/clients that read the
description text know to pass workspace_id (and to call list_workspaces
first). Global tool descriptions are left untouched.

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

* refactor(mcp): trim multi-workspace tool/arg descriptions

The workspace_id note repeats across every workspace-scoped tool in each
tools/list, so keep it terse: description suffix "Requires `workspace_id`."
and arg description "Target workspace id (from list_workspaces)." to avoid
spending tokens on repeated boilerplate.

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

* fix(mcp): enforce script/flow path scopes for multi-workspace run-by-path

In multi-workspace mode runScriptByPath/runFlowByPath are the only way to run
scripts/flows, but they were authorized against the endpoint scope only — never
the caller's mcp:scripts:/mcp:flows: path scopes. A granular token could run
items outside its allowed paths (e.g. mcp:scripts:f/team/* + mcp:endpoints:*
running f/other/secret), and a mcp:endpoints:* token could run arbitrary
scripts.

Now these two endpoints are authorized by the script/flow scope of the
requested path (matching single-workspace mode's per-item tools): exposed in
list_tools only when the token grants some script/flow (McpScopeConfig::has_any),
and at call time the path is checked via is_allowed("script"/"flow", path).

Verified e2e: mcp:scripts:f/team/* runs f/team/* but is denied f/other/*;
mcp:endpoints:* alone no longer exposes or runs run-by-path.

Reported by Codex + Pi review on #10043.

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

* fix(mcp): deny run-by-path for mcp:favorites multi-workspace tokens

mcp:favorites sets granular=false, so the previous run-by-path scope check
(gated on `granular`) was skipped entirely — a default "Favorites only"
all-workspaces token could run any script/flow by naming its path, bypassing
the favorites restriction.

Favorites are an enumerated set reachable only through per-item tools, not by
arbitrary path, so they grant nothing for run-by-path. has_any() now returns
true only for mcp:all (not favorites), and the call-time check drops the
`granular` gate and relies on is_allowed() directly (already false for
favorites, true for mcp:all, pattern-matched for granular).

Verified e2e: mcp:favorites no longer exposes or runs run-by-path; mcp:all
still runs; granular script scopes still path-enforced.

Reported by Codex review on #10043.

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-10 23:32:30 +02:00
Ruben Fiszel 38a190b53a chore(main): release 1.754.0 (#10017)
* chore(main): release 1.754.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-10 13:59:22 +00:00
Ruben Fiszel 9feda57c15 perf: index v2_job(parent_job) to speed up run child-job listing (#10034)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 07:51:16 +00:00
Ruben Fiszel 9ad6927231 chore(main): release 1.753.0 (#9997)
* chore(main): release 1.753.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-08 16:46:15 +00:00
Ruben Fiszel f28ea9cb99 feat(db-health): add connection sizing guidance (#10014)
* feat(db-health): add connection sizing guidance

The Database Connections panel showed current/max connections but gave no
guidance on how to size max_connections for the deployment. Derive an estimate
from the live worker fleet: each worker instance shares a pool sized
DEFAULT_MAX_CONNECTIONS_WORKER + (workers - 1), and each server opens up to
DEFAULT_MAX_CONNECTIONS_SERVER (both overridable via DATABASE_CONNECTIONS).

The endpoint now returns live worker/instance counts, the default per-server
and per-worker pool sizes, the estimated peak worker connections, the reserved
superuser connections, and a recommended max_connections floor (workers + one
server + 25% headroom). Servers do not ping worker_ping, so the recommendation
assumes one server and exposes the per-server increment. The panel renders this
as a sizing breakdown and warns when max_connections is below the recommended
floor.

Fixes WIN-2147

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

* refactor(db-health): single source for pool-size constants + sizing tests

Address review: db_connect.rs kept its own copies of DEFAULT_MAX_CONNECTIONS_*
that duplicate the windmill_common constants the sizing guidance reads, so
tuning the runtime pool size would silently leave the guidance stale. Re-export
the windmill_common constants from db_connect.rs so there is one source of truth.

Add unit tests for compute_connection_sizing covering the zero-fleet, single
worker, multi-instance, and reserved-clamp cases.

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

* feat(db-health): 20% headroom and 200-connection minimum floor

Lower the sizing headroom from 25% to 20% and never recommend below 200
connections (postgres defaults to 100; cheap headroom for growth/bursts/psql).
Update the guidance message and unit tests accordingly.

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

* fix(db-health): honor DATABASE_CONNECTIONS in sizing recommendation

Address Codex P1: the runtime caps every process's pool at DATABASE_CONNECTIONS
when set (db_connect.rs), but the sizing guidance always used the default 50/5
pools. For a tuned deployment this under-estimated worker demand and could hide
a genuine under-provisioning (e.g. DATABASE_CONNECTIONS=100 with 5 instances is
500 worker connections, not 25).

compute_connection_sizing now takes the effective DATABASE_CONNECTIONS override
(read the same way db_connect.rs reads it): when set, each worker instance and
server pool is that value and the worker estimate is override * instances. The
response exposes server_pool_size / worker_pool_size (effective) and
database_connections_override; the panel renders both pool rows and labels them
(default) vs (DATABASE_CONNECTIONS), and the message states which source is used.
Adds a unit test for the override path.

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

* fix(db-health): exclude agent workers from connection sizing

Agent workers reach the API over HTTP (MODE=agent, Connection::Http) and hold
no postgres pool, but their pings still land in worker_ping (written server-side
by /api/agent_workers/update_ping). Counting them inflated the connection
estimate. Filter the fleet query by the worker-name prefixes: DB-connected
workers use "wk-" (WORKER_NAME_PREFIX), agent workers use "ag-"
(AGENT_WORKER_NAME_PREFIX). Only wk- workers/instances feed the estimate; ag-
workers are counted separately and surfaced as context ("N agent workers
excluded — they use HTTP, not postgres connections"). Adds a unit test.

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-08 16:42:39 +00:00
Ruben Fiszel 223e1569ce chore(main): release 1.752.0 (#9974)
* chore(main): release 1.752.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-07 22:10:10 +02:00
Diego Imbert e47aedac0a feat: add SQL migrations for data tables (#9693)
* feat: add datatable_migrations table

* feat: add route to run datatable migrations

* feat: sync datatable migrations as .up.sql/.down.sql files

* feat: add datatable migrate up/down commands and post-push run prompt

* feat: add datatable migrate new command to scaffold migrations

* feat: add datatable migrations management UI

* feat: prompt to create migration on DDL in datatable SQL editors

* feat: support running a single specific datatable migration

* feat: view migration content, run single migration, fix stacked modal

* feat: per-row revert button with out-of-order warning

* fix: avoid migrations list flicker on refresh after an action

* feat: generate initial datatable migration via pg_dump

* fix: surface datatable migration API error details in toasts

* fix: revert created migration if create-and-run fails to run

* fix: include postgres error detail in migration run/rollback failures

* feat: sync datatable migrations as files via the workspace export

* refactor: move datatable migrations to migrations/datatable/ path

* fix: drop redundant datatable_migration label in sync output

* fix: exclude datatable migration sql files from script metadata generation

* feat: run datatable migrations as user-permissioned labeled jobs

* feat: reject invalid datatable migrations on sync push

* feat: datatable migrate up/down default to all datatables, --datatable to target one

* fix: surface postgres error detail when datatable migrations fail to run

* chore: regenerate CLI docs for datatable migrate commands

* feat: default new datatable migration to a BEGIN/END transaction template

* fix: validate datatable migration name and datatable at the API boundary

* fix: ensure detected DDL ends with semicolon when wrapped in transaction

* fix: re-prompt instead of stripping DDL when new-migration modal is cancelled

* feat: refresh datatable schema after running a migration from the SQL REPL

* feat: record db manager DDL on data tables as migrations

* feat: make datatable migrations opt-in per data table

* fix: make migration view editor read-only so its code can scroll

* fix: don't re-prompt DDL guard when creating a migration without running

* feat: generate down migrations for db manager DDL (postgres)

* fix: correct down migration for db manager alters (no double-wrap, serial)

* feat: explain migrations purpose with a tooltip in the migrations modal

* compare paeg

* feat: add datatable_migration kind to workspace diff pipeline

* chore: point ee-repo-ref at datatable_migration git-sync companion

* fix: harden datatable migration version allocation and initial-migration bookkeeping, add tests

* feat: deploy and run datatable migrations on workspace merge

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

* Refactor + handle datatable setting delete/rename

* refactor: move datatable migration rename/delete cascade into module

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

* chore(windmill-utils-internal): bump to 1.7.1 for datatable migration deploy provider methods

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

* feat(db-manager): add Migrations button to top bar, make Refresh icon-only

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

* BEGIN/END placeholder in down migration

* feat: autofocus migration name input and flag it red when empty

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

* feat(datatable-migrations): allow non-admins to create/run/revert migrations, gate only opt in/out

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

* border nits

* refresh db manager schema on migrations

* BEGIN/END scaffold in CLI

* feat(cli): push local datatable migrations before running on migrate up

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

* feat: flag invalid migration name with red border, not just empty

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

* refactor: drop random slug from auto-generated migration names

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

* feat: offer revert-and-delete when deleting an installed migration

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

* feat: record fork merge as a migration when target datatable opts in

* nit

* clone migrations on fork

* windmill-utils-internal

* fix(datatable-migrations): serialize run/rollback with a per-db advisory lock

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

* fix(db-manager): fail closed when migrations-status check errors on DDL apply

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

* docs: fix generate_initial migration ordering comment to match code

* chore(datatable-migrations): remove unused update_datatable_migrations endpoint

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

* fix: run DDL migration guard on the script editor Test button

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

* split

* ee-repo-ref

* chore(frontend): sync package-lock with package.json (@emnapi deps)

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

* fix(datatable-migrations): never resolve instance credentials into migration job args

datatable_database_arg eagerly resolved instance data-table credentials
(including the shared instance-wide Postgres password) and passed them as the
migration job's plaintext `database` arg, landing in v2_job.args. Since the
run route has no admin gate, a non-admin could run a migration and read
args.database to recover the password, granting cross-workspace psql access to
all instance data-table DBs.

Pass a `datatable://<name>` reference for both resource-backed and instance
data tables instead; the pg executor already resolves it to real credentials
server-side at run time, so nothing sensitive is ever stored in the job args.

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

* nit

* fix: handle dollar-quoting and comments when splitting SQL statements

* feat: deploy datatable migrations on merge with explicit opt-in error

* fix(frontend): sync package-lock with npm 11 peer-dep resolution

npm ci failed with 'Missing: @emnapi/core@1.11.2 / @emnapi/runtime@1.11.2 from
lock file'. @napi-rs/wasm-runtime declares @emnapi/core|runtime ^1.7.1 as
peerDependencies while @rolldown/binding-wasm32-wasi pins them to exactly
1.10.0. Newer npm (bundled with node 24 in CI) installs the peer deps at the
highest match (1.11.2) alongside rolldown's nested 1.10.0, so the ideal tree
needs both versions; the committed lock only had 1.10.0.

Regenerate the lock with npm 11.18 so it carries both 1.11.2 (top-level, for
the peer deps) and 1.10.0 (nested, for rolldown's pin). Verified npm ci passes.

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

* nit npm publish

* fix: fail closed on migrations-status error in fork schema merge

* nit CI emnapi/core version

* prevent initial_datatable_migration if migrations already exist

* fix(datatable-migrations): validate persisted data table names as path segments

edit_datatable_config only validated rename segments, not the actual
settings.datatables keys, so a data table could be saved directly under a name
like '..' or one containing '/'. Since new tables default to
migrations_enabled = true, generate_initial_datatable_migration would then
insert a migration row and the sync export would build
migrations/datatable/<name>/... paths from that name, producing malformed or
directory-escaping export paths.

Validate every persisted data table name in edit_datatable_config (alongside
the existing rename checks) and add validate_datatable_path_segment to
generate_initial_datatable_migration for defense in depth.

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

* fix: scope datatable _wm_migrations by data table and cascade renames/deletes

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

* fix(system_prompts): resolve nested local command groups in CLI docs generator

The CLI docs generator anchored on the first `new Command()` in a file and
never resolved locally-defined command groups passed as
`.command("name", localCmd)`. For datatable this flattened the nested
`migrate` group: it emitted `datatable new/up/down` plus a bare
`datatable migrate`, and mislabeled the datatable command with the migrate
group's description. jobs was broken the same way (its description was pull's,
and pull/push rendered empty).

Anchor block extraction on the `export default`ed command, recurse into
locally-defined `const x = new Command()` groups mounted as subcommands, and
render nested sub-subcommands. Regenerated docs now show
`datatable migrate new/up/down` and `jobs pull/push` with their real
options.

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

* refactor: drop unreleased _wm_migrations legacy-upgrade handling

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

* fix: return datatable migration SQL from getItemValue for the diff drawer

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

* chore(frontend): use windmill-utils-internal 1.8.2 for migration diff drawer

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

* nit

* nit

* fix: handle datatable migration renames on push and dedupe timestamps

* fix: reject rewriting an already-applied datatable migration on upsert

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

* fix(frontend): add missing @emnapi/core and @emnapi/runtime lockfile entries

Resolves npm ci EUSAGE failure: the optional cpu:wasm32 @rolldown/binding-wasm32-wasi
declares deps on @emnapi/core@1.11.2 and @emnapi/runtime@1.11.2 that had no resolved
lockfile entries.

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

* fix(cli): datatable migrate up/down default to main datatable, not all

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

* fix: fail closed when applied status unreadable on datatable migration rewrite

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

* fix: surface full error detail in Database Manager DDL/query errors

* "See migration" button in the toast

* feat: add Enter shortcut to Create-a-migration in the DDL guard

* fix(frontend): warn before running a newly-created datatable migration out of order

The row-level Run action warns when earlier migrations are still pending, but
the create-and-run paths ran a just-created migration with `only` directly,
applying it ahead of older pending migrations without that confirmation.

Reuse the same "Run migration out of order" confirmation across all
create-and-run paths via a shared helper (datatableMigrationUtils):
- NewDataTableMigrationModal "Create and run" (and the DDL guard path)
- DatatableSchemaDiff fork→parent merge
- dbOps schema ops (DB manager create/alter/drop) — the pure factory throws a
  MigrationRunCancelled sentinel on decline, which DBTableEditor treats as a
  silent cancel

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

* fix: keep renamed datatable migrations visible in compare view

* fix: record per-migration deployment on datatable migrations disable

* fix(cli): run deployed datatable migrations after workspace merge

The merge command upserted datatable_migration definitions into the target
workspace and reported the item as successfully deployed, but never ran the
migrations. For forked datatables backed by separate databases, this left the
target schema unchanged until someone manually ran `wmill datatable migrate up`,
while the CLI reported a successful merge.

Collect the datatable migrations deployed (not deleted) into the target and,
after the deploy loop, offer to run them via the existing offerToRunNewMigrations
helper — the same post-deploy run prompt the push/sync path uses (interactive
only; `--yes`/non-TTY skip the mutating run, matching push behavior). Export
parseDatatableMigrationDeployPath so the merge path can parse the deployed items.

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

* fix(backend): serialize datatable migration edits/deletes with the run lock

A migration run snapshots a migration's code_up from datatable_migrations and
only records its version in the data table's _wm_migrations after the job
succeeds. upsert_datatable_migration checked _wm_migrations before allowing an
edit but took no lock, so a concurrent edit could read "not applied yet",
rewrite code_up/code_down, and then the in-flight run would record the version
for the old SQL — leaving _wm_migrations pointing at SQL that was never applied
(migrate up then skips it; rollback runs a down that doesn't match).

Serialize definition rewrites and deletes with the same per-database advisory
lock the run/rollback paths use:
- Factor the connect+advisory-lock into lock_datatable_migration_runs and the
  applied-versions read into read_applied_versions_on_client.
- run_datatable_migrations now snapshots the definitions AFTER taking the lock,
  so code_up can't change between snapshot and version-record.
- upsert (when changing an existing def) and delete take the lock across the
  applied-check and the write; delete now rejects deleting an already-applied
  migration (would orphan its _wm_migrations record), symmetric with upsert.
  Both fail closed if the data table database is unreachable.

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

* fix(frontend): stack the out-of-order migration confirm above the DB editor preview

Creating a table on a migrations-enabled data table opened the DB table editor's
"Confirm running the following" preview modal, whose confirm triggers applyDdl,
which then asks for out-of-order confirmation. Both are ConfirmationModals with a
hardcoded z-[9999]; the out-of-order one lives in DBManagerContent (mounted before
the editor), so it rendered behind the still-open preview modal.

Add an optional zIndexClass prop to ConfirmationModal (default z-[9999],
backward-compatible) and give the DB-manager out-of-order confirm z-[10000] so it
stacks on top.

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

* chore: update ee-repo-ref to 27672e37df5d9dfde94f19963d5ffcdf8dd5448c

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

Previous ee-repo-ref: 6c287041cd7edd4a77a4bc07ad0e156cec32cce4

New ee-repo-ref: 27672e37df5d9dfde94f19963d5ffcdf8dd5448c

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-07 08:25:16 +00:00
Ruben Fiszel 8dd5e48a68 chore(main): release 1.751.0 (#9965)
* chore(main): release 1.751.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-06 19:00:48 +00:00
Ruben Fiszel 97d14d979f bun bootstrap housekeeping on the migrator's held connection (#9970)
migrate() and fix_flow_versioning_migration re-acquired a second connection from the pool while already holding one (the migrator's checked-out, advisory-locked connection). That deadlocks any backend limited to one connection at a time — connection-constrained managed Postgres, PgBouncer transaction pooling, or an embedded single-connection dev database. Route those housekeeping queries onto the already-held connection via a new CustomMigrator::connection() accessor. Fewer connections during migration and, for fix_flow_versioning, the existence check and write now run on the same advisory-locked connection. Default multi-connection behavior is unchanged.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 18:59:25 +00:00
hugocasa fd8e64d11f feat: add cosmetic dev/staging label for dev workspaces (#9959)
* feat: add cosmetic dev/staging label for dev workspaces

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

* feat: prefill dev fork name and use a link to switch its label

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

* style: reword the dev/staging label link copy

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

* style: preview the dev/staging label as a badge in the switch link

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

* feat: show the dev/staging badge in the session diff drawer header

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-06 18:43:17 +00:00
Ruben Fiszel 5fe7e1f3e8 chore(main): release 1.750.0 (#9952)
* chore(main): release 1.750.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-06 11:39:57 +02:00
windmill-internal-app[bot] aaeb9524b3 chore: refresh vendored docs snapshot (#9955)
Co-authored-by: hugocasa <15649739+hugocasa@users.noreply.github.com>
2026-07-06 10:01:13 +02:00
Ruben Fiszel 891b32195a chore(main): release 1.749.0 (#9938)
* chore(main): release 1.749.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-06 01:40:42 +02:00
Ruben Fiszel 46be39dfb7 fix(pipelines): order data_test relationships refs before the tested script in a cascade (#9934)
* fix(pipelines): order data_test relationships refs before the tested script in a cascade

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

* fix(pipelines): key custom-test reads by (usage_kind, path) to avoid same-path flow collisions

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-05 22:34:58 +02:00
Ruben Fiszel 799b9e3b7c chore(main): release 1.748.0 (#9914)
* chore(main): release 1.748.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-05 18:23:51 +02:00
Ruben Fiszel 39eb9de1bc feat(pipelines): fork data environments for ducklake materialization (dev data) (#9915)
* feat(pipelines): fork-scoped ducklake namespaces with read-defer to parent

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

* feat(pipelines): fork graph indicator + fork ducklake namespace cleanup endpoint

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

* feat(pipelines): fork_views-keyed view transition, fork lineage clone, design doc

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

* fix(pipelines): review hardening - fork DATA_PATH last-wins, registry cache TTL, defer tests

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

* feat(pipelines): per-lake isolated/shared choice at fork creation

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

* fix(pipelines): chain-aware defer discovery + per-location fork namespace registry

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

* fix(pipelines): lake-scoped fork schemas, catalog identity in registry, chain-aware graph chips

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

* fix(pipelines): cleanup deletes fork data from the registered storage identity

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

* fix(pipelines): collapse fork data-path segment to one component (slash-safe ids)

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

* fix(pipelines): per-catalog ancestor checks, ancestor extra_args passthrough, test compile fix

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

* fix(pipelines): invalidate fork ancestor-chain cache on lineage mutations

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

* fix(pipelines): sweep descendant ancestor-chain caches on delete/reparent

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

* fix(pipelines): run fork ducklake cleanup inline in delete_workspace

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

* fix(pipelines): resolve fork cleanup credentials pre-commit, destroy post-commit

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

* fix(pipelines): shared dev-workspace authz gate for namespace drop, invalidatable registration cache, segment-boundary delete filter

- extract require_prod_admin_for_dev_workspace, used by both delete_workspace
  and drop_forked_ducklake_namespaces so the gates cannot drift
- key FORK_DUCKLAKE_REGISTERED per workspace and invalidate it in
  cleanup_fork_ducklake_namespaces so a same-id fork recreated within the TTL
  re-registers its namespaces
- filter listed object locations to the segment boundary before deletion

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

* fix(pipelines): keep orphaned wm-fork-* workspaces ducklake-isolated

parent_workspace_id is ON DELETE SET NULL, so a fork can outlive its
parent with an empty ancestor chain while its cloned config still points
at the shared lake. Key the isolation gate on the wm-fork- prefix as well
as the chain (mirroring workspace_is_fork): orphaned forks get the write
redirect, registration and cleanup with zero ancestors (no defer), and
keep their 'fork' graph chips.

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

* fix(pipelines): attach orphaned wm-fork-* ancestors at their fork namespace

Chain position alone classified the last ancestor as a root, but an
orphaned wm-fork-* ancestor (its own parent deleted, SET NULL) ends the
chain the same way while its data lives in its fork namespace — its
descendants' defer views bound the dead root's lake instead. Key the
root-vs-fork decision on the wm-fork- prefix too, matching the
resolution gate.

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

* fix(pipelines): never inherit shared lake opt-out; durable cleanup ledger for failed fork deletions

- fork creation strips cloned fork_behavior stamps before applying the
  request's shared_ducklakes list: sharing is a per-creation choice, a
  fork of a shared fork defaults back to isolated
- fork_ducklake_namespace loses its ON DELETE CASCADE FK: rows are the
  durable cleanup ledger and outlive the workspace when physical cleanup
  fails post-commit; fork creation retries leftover rows for the reused
  id and refuses to create while a metadata schema still cannot be
  dropped (data-file leftovers alone are inert once the schema is gone
  and are swept by the next successful same-prefix cleanup)

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

* fix(pipelines): make orphaned-namespace cleanup retries independent of deleted fork resources

- ledger rows gain a schema_dropped phase flag: set when the schema drop
  succeeded but data cleanup failed, so later retries skip the schema
  phase and need no catalog credentials at all; registration resets it
  on re-attach (ON CONFLICT DO UPDATE) since attaching recreates the
  schema
- retry-path $res: resolution falls back to the workspace being forked
  (the deleted fork's resources were clones of a parent's); live paths
  (delete_workspace prepare, drop endpoint) pass no fallback

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

* fix(pipelines): fork tables from failed-after-commit runs stay fork-owned in defer and graph

A failed materialization must not disguise a physically existing fork
table as deferred: CREATE VIEW IF NOT EXISTS silently yields to the
table, so reads hit fork data while the graph claims parent defer.

- record_mat upsert preserves the last committed snapshot_id on failure
- defer discovery and graph chips treat fork rows with a committed
  snapshot as fork-owned even when status is failed
- inspect_fork_catalog also lists live fork tables (same round trip) and
  the defer list is filtered against them — covers rows recorded before
  this fix and tables created by raw SQL
- drop stale FK-cascade wording in the design doc and sidebar comment

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

* feat(pipelines): fork-mode ducklake settings — per-lake isolated/shared chips + banner, fork_behavior round-trip

The workspace-settings ducklake editor had no fork awareness: no
reminder of each lake's isolated/shared choice and no warning about
what edits mean in a fork. It also rebuilt each lake explicitly on
save, silently dropping fork_behavior — any settings save in a shared
fork flipped the lake back to isolated.

- fork detection mirrors the backend gate (parent link or wm-fork- prefix)
- info banner explaining isolated vs shared semantics in a fork
- per-lake chip (emerald 'isolated' / amber 'shared with parent') with
  tooltips, matching the pipeline graph chip colors
- fork_behavior added to DucklakeSettingsType and preserved through
  convertDucklakeSettingsToBackend

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 09:58:06 +02:00
Ruben Fiszel 33521505db feat(ducklake): scheduled lake maintenance (expiry, compaction, orphan cleanup) (#9916)
* feat(ducklake): scheduled lake maintenance (snapshot expiry, compaction, orphan cleanup)

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

* fix(ducklake): review fixes — starts_with not LIKE, CE license-lapse escape

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

* docs(ducklake): auth-contract docs + _unchecked rename per codex review

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

* refactor(ducklake): move maintenance payload construction into EE module

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

* fix(ducklake): fall through to script resolution for non-managed reserved-prefix schedules

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

* docs(ducklake): document accepted pre-existing-schedule limitation on the reserved prefix

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

* fix(ducklake): CE save-off clears the managed schedule row and queued occurrence

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

* chore: update ee-repo-ref to 2fab310d4f50ed7c34857d69c9b854f4491bf217

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

Previous ee-repo-ref: fff1fd830a36beba732486f05941ec243cf6b640

New ee-repo-ref: 2fab310d4f50ed7c34857d69c9b854f4491bf217

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>
2026-07-04 17:23:23 +02:00
Ruben Fiszel 42e11c6570 feat(pipelines): schema contracts — save-time consumer checks vs captured schemas (#9917)
* feat(pipelines): schema contracts — save-time consumer checks vs captured schemas

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

* refactor: move schemaContractContext above schemaCanEvolve doc comment

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

* fix: emit scd2/on_schema_change in CLI local graph, address review notes

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

* fix: gate editor _current ignore-suppression on scd2, matching backend

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 10:40:00 +02:00
Ruben Fiszel 5d7fb6deca feat(pipelines): asset freshness — fresh/stale badge (CE) + watchdog (EE) (#9909)
* feat(pipelines): passive asset freshness tracking on the graph

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

* chore(pipelines): drop dead freshness-enforcement stub, document query ordering

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

* feat(pipelines): freshness watchdog (EE) — auto re-run stale producers

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

* fix(pipelines): watchdog review fixes — archived workspaces, badge kind parity, scan index

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

* fix(pipelines): CI review — no singlestepflow in freshness, +N parity, completion-time fallback

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

* fix(pipelines): CI review — history completedAt, freshness/asset trigger UI metadata

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

* chore: update ee-repo-ref to 6f5fe0f7f56696fbef5a8349da38496c32e71666

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

Previous ee-repo-ref: 1f13380354bf591ae25a2c20d36917534bcc5459

New ee-repo-ref: 6f5fe0f7f56696fbef5a8349da38496c32e71666

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>
2026-07-04 06:23:44 +02:00
Ruben Fiszel df6e511763 chore(main): release 1.747.0 (#9901)
* chore(main): release 1.747.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-03 19:40:01 +02:00
hugocasa d600c7ecfe fix(ai): route Azure Foundry Claude models via Anthropic Messages API (#9908)
* fix(ai): route Azure Foundry Claude models via Anthropic Messages API

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

* fix(ai): keep explicit Azure OpenAI deployment base URLs intact

build_azure_openai_url only appends /openai/v1 for a bare resource root; any base with an explicit path (e.g. .../openai/deployments/<id>) is preserved. Adds a regression test and a unit test for usesAnthropicMessagesApi.

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

* feat(ai): enable Claude extended thinking on Azure Foundry

Route azure_foundry+Claude through the Anthropic reasoning branch (adaptive thinking + output_config.effort) instead of the gpt/o gate, and recognize claude-sonnet-5. Live-verified: sonnet-5 and opus-4-8 on Foundry accept the low/medium/high/xhigh/max ladder and render summarized thinking.

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-03 18:26:12 +02:00
Ruben Fiszel 3ec1f164be fix: strip NUL characters from app values at save time (#9903)
App values are persisted to a json column, which permits the JSON NUL
escape (backslash-u-0000), but are later converted to jsonb (e.g. a
workspace fork clone_apps, search indexing), which rejects it with
"unsupported Unicode escape sequence" -- silently making the app
un-forkable. The usual source is a binary file such as .DS_Store
accidentally bundled into a raw app file map.

A real NUL is unstorable in jsonb either way, and frontend code that
needs the character writes it as the source escape (which JSON-encodes
to an escaped backslash + literal u0000 and is left untouched), so rather
than hard-failing the save we strip genuine NULs and warn.

Add strip_null_chars and apply it at both app_version insert sites
(create_app_internal and update_app_internal, covering the regular and
raw create/update routes). It removes a genuine NUL escape (odd run of
backslashes before u0000) while preserving an even run. Returns a
borrowed Cow (no allocation) when the value is already clean. Covered by
unit tests.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 15:58:56 +02:00
Ruben Fiszel fad5419b9d chore(main): release 1.746.0 (#9872)
* chore(main): release 1.746.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-03 01:03:44 +02:00
Ruben Fiszel 84141add1d feat(pipelines): workspace duckdb macro libraries (// macros / // use) (#9890)
* feat(pipelines): parse duckdb macro-library annotations (// macros, // use)

* feat(pipelines): duckdb macro registry tables + deploy-path validation and writes

* feat(pipelines): inject workspace duckdb macros into consumer jobs at run time

* feat(pipelines): surface macro libraries and lib-consumer edges in asset graph api

* feat(frontend): macro-library nodes, lib-consumer edges and scaffold in pipeline graph

* docs: mark dbt gap #7 (packages/macros) shipped via workspace macro libraries

* fix(pipelines): review fixes - char-safe parsing, local macros win, fork clone, trust-model docs

* feat(frontend): duckdb macro autocomplete + workspace macro explorer drawer

* fix(pipelines): address CI review - use-setup retention, splice past local defs, orphan filter, full consumer rescan, index-keyed strip

* fix(pipelines): inject provider library setup for implicitly-called macros too

* fix(pipelines): rls-gate macro listing + honor library-level // use transitively

* fix(pipelines): weave injected macros around local definitions by bind order

* fix(pipelines): injected library setup always runs before user blocks

* perf(pipelines): cache macro registry per workspace with notify-event invalidation

* perf(pipelines): disable macro registry cache on cloud
2026-07-03 00:59:30 +02:00
Ruben Fiszel af01e90b5c feat(s3): replace CE 50MB upload cap with 10GiB workspace storage quota (#9874)
* fix(s3_proxy): enforce CE 50MB upload cap on multipart uploads

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

* feat(s3): replace CE 50MB upload cap with 10GiB workspace storage quota

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

* fix(s3): gate CE quota OSS stubs to not(enterprise) to match callers

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

* fix(s3): delta-aware CE storage quota + guard usage-load retry loop

Account for the overwritten object's size in the quota check so valid
same-size overwrites near quota are not rejected (Codex review), and stop the
storage-usage $effect from re-firing on persistent API errors (Pi review).

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

* fix(s3): count chunked PUTs; revert overreaching volume quota copy

Volumes write to workspace storage via a separate worker-side path with its own
50MB-per-file cap that this PR does not change, so revert the drawer copy that
claimed they count toward the 10GiB quota (Codex review). Bump ee-repo-ref for
the chunked-PUT accounting fix.

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

* fix(s3): add SQLx cache for CE usage-bump/quota queries; exclude volumes

Regenerate the missing offline SQLx cache for the not(enterprise) bump and
remaining-quota queries so the private CE offline build compiles, and bump
ee-repo-ref for the volumes/-prefix exclusion from the counted quota (Codex
review).

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

* fix(s3): always HEAD for CE upload delta so overwrites don't inflate usage

Bump ee-repo-ref for the fast-path overwrite-accounting fix (Codex review).

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

* fix(s3): reserve volumes/ prefix on CE write surfaces to close quota bypass

Reject direct writes to the reserved volume prefix on the app-upload surface and
add the OSS stub; bump ee-repo-ref (Codex review).

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

* fix(s3): refuse new multipart work when CE workspace is at quota

Bump ee-repo-ref for the multipart-initiate/part quota gate (Codex review).

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

* feat(s3): reserve in-flight multipart bytes against CE storage quota

Add workspace_multipart_inflight table + grants, SQLx cache for the reservation
queries, and bump ee-repo-ref. Bounds abandoned multipart uploads that the
list-based recount can't see (Codex review).

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

* fix(s3): clear multipart reservation only after a successful complete

Add exclude-upload arg to the OSS quota stub/caller and the SQLx cache for the
updated remaining-quota query; bump ee-repo-ref (Codex review).

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

* fix(s3): per-part multipart reservation; commit only on part success

Per-part workspace_multipart_inflight schema (upload_id, part_id) so retries
replace rather than double-count; SQLx cache for the reworked queries; bump
ee-repo-ref (Codex review).

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

* perf(s3): HEAD the multipart overwrite target once per upload, not per part

SQLx cache for the stored-credit lookup; bump ee-repo-ref.

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

* chore: update ee-repo-ref to bea5a8b5120d6d69cab1ad4611ebe463559bd200

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

Previous ee-repo-ref: 6e6ff86f1939cf74736b7d435bf6851416437523

New ee-repo-ref: bea5a8b5120d6d69cab1ad4611ebe463559bd200

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>
2026-07-03 00:57:19 +02:00
hugocasa 7c7d7474cc feat: support workspace forks on cloud using parent workspace limits (#9864)
* feat: support workspace forks on cloud using parent workspace limits

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

* docs: clarify count_paid_seats approximates rather than mirrors billing seats

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

* fix: non-admin fork UI, attach cap, and fork-count for cloud forks

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

* fix: cloud fork billing cache on rename, usage display, attach cap edge

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

* feat: fork count in cloud quotas + fork billing points to parent

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

* fix: invalidate billing/fork caches on fork deletion for id reuse

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

* fix: gate fork usage remap on CLOUD_HOSTED, not just the cloud feature

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

* docs: note cloud feature vs CLOUD_HOSTED gating in backend guide

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

* fix: reserve fork-cap slots for an attach candidate's whole subtree

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

* fix: invalidate team-plan cache on delete, raise fork depth cap

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

* feat: cap fork nesting depth (MAX_FORK_DEPTH, default 5)

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

* fix: fork count/height robust to cycles and deleted intermediates

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

* fix(frontend): reset fork button loading state on creation error

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

* fix: invalidate billing cache for attached fork subtree; helper auth docs

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-02 23:59:02 +02:00
hugocasa d9b080f57f feat(ai): add Azure AI Foundry as a native AI provider (#9879)
* feat(ai): add Azure AI Foundry as a native AI provider

Adds `azure_foundry` as a new AIProvider variant wired through the AI
chat (copilot) and AI agent flow steps. Foundry's chat completions API
is OpenAI-compatible and uses Azure conventions (api-key header, Azure
URL building), so it reuses the existing OpenAI-compatible query builder
and proxy path via the shared `is_azure` helper (renamed from
`is_azure_openai`).

Backend (windmill-ai):
- New `AzureFoundry` enum variant (serde `azure_foundry`)
- `get_base_url` requires a resource base URL (like Azure OpenAI / Custom)
- `is_azure()` covers Azure OpenAI + Foundry (api-key auth, Azure URL)
- Added to OpenAI-compatible proxy support and HttpForward proxy mode
- New proxy URL unit test

Frontend (copilot):
- New provider entry, completion config, model-token handling, streamed
  usage tracking, and reasoning registry (all model-id-gated, so a no-op
  for Foundry's non-OpenAI catalog)
- Treated as a chat-completions provider, not the OpenAI Responses API

OpenAPI:
- `azure_foundry` added to AIProvider (openapi.yaml) and AIProviderKind
  (openflow.openapi.yaml); regenerated CLI guidance

Note: the `azure_foundry` resource type (base_url + optional api_key) is
hub-managed and must be published to the Windmill Hub separately.

Fixes WIN-2122

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

* fix(ai): add azure_foundry to copilot flow Zod provider enum

The tracked copilot flow schema (openFlowZod.gen.ts and its openFlow.json
source) still carried the old AIProvider enum, so validateFlowModules /
validateSpecialFlowModule rejected AI-generated flow edits that create or
update an aiagent module with provider kind "azure_foundry" before they
could be saved. Add the value to both (preserving the generated single-line
format) and a regression test over the flow-module validation path.

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

* feat(ai): lead provider list with OpenAI, Anthropic, Google AI

Reorder AI_PROVIDERS so the three primary direct providers come first. The
AIProviderPicker renders the first three entries as quick-access buttons, so
these become the defaults (previously OpenAI, Azure OpenAI, Azure Foundry);
Azure OpenAI / Azure Foundry stay adjacent right after. No logic depends on
provider order (only per-provider defaultModels[0] is read).

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-02 23:42:44 +02:00
Ruben Fiszel 53bbb92953 feat(pipeline): backfill a range of partitions from the asset drawer (#9885)
* feat(pipeline): backfill a range of partitions from the asset drawer (ee)

* feat(pipeline): cancel in-flight backfill job and show cancelling state

* refactor(pipeline): move backfill range logic behind private feature

* fix(pipeline): close backfill cancel-launch race and record dispatch intent

* docs(openapi): producer_path also covers SDK write-edge producers

* chore: update ee-repo-ref to c3852ecb36bd0be1a74c63169e513888f3347850

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

Previous ee-repo-ref: 7c1450ef89fbc9e844a121b39cafe0d7235d704b

New ee-repo-ref: c3852ecb36bd0be1a74c63169e513888f3347850

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-02 12:50:55 +02:00
Ruben Fiszel e77b7523a5 nit enterprise implies license feature 2026-07-02 06:01:22 +00:00
Ruben Fiszel 9a24cd2bef chore(main): release 1.745.0 (#9858)
* chore(main): release 1.745.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-02 00:15:58 +02:00
Ruben Fiszel 1a9debb689 fix(jobs): give flow dynselect a path and its worker tag, like scripts (#9867)
Fetching options for a `dynselect`/`dynmultiselect` input was inconsistent
between deployed scripts and deployed flows:

- scripts ran through `push_script_job_by_path_into_queue` — a `script` job
  with the script's path, tag, lock and codebase resolution;
- flows ran their schema dyn-select code as an anonymous `preview` with no
  path and no tag (always the language default), and reported access
  failures as a raw `SqlErr: no rows`.

Deployed scripts are left exactly as they were (that path already handles
tag/lock/codebase/on-behalf-of correctly). The flow branch now:
- carries the flow path on the preview job,
- reads the flow's `tag` under RLS and routes the job to it (falling back to
  the language default when unset), matching the script's worker group, and
- runs `check_tag_available_for_workspace` on that tag — the same gate a
  normal flow run and the script path apply — so a caller who can read the
  flow but is not allowed to use its (custom/scoped) worker tag is rejected
  consistently.

The flow's tag read runs on every request, so it also serves as the
per-request access check, replacing the raw error with a clean
`NotAuthorized` / `NotFound`. Entrypoint-name validation now covers all
branches (it is interpolated into the generated wrapper). Inline is
unchanged: a `preview` with no path on the language default, blocked for
operators.

Fixes WIN-2118

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 00:09:56 +02:00
Ruben Fiszel 20cd1a02d5 feat(forks): partial-visibility deploy + surface hidden items (#9868)
* fix(forks): let partial-visibility users deploy the visible subset

The fork Compare & Deploy page hid the deploy button entirely whenever the
comparison reported any item not visible to the user (all_ahead/all_behind
flags), telling them to hand the deploy to someone with full access. But the
non-visible items are already filtered out of the diff list, and the UI already
supports deploying an arbitrary subset via per-item selection — so blocking
everything was inconsistent and, for stale/phantom rows, blocked on items that
don't even exist.

Show the deploy footer regardless; the user acts on the visible/selected items
(the per-item disabled conditions are unchanged). The hidden-items notice is
kept but downgraded to a non-blocking, direction-scoped banner that explains the
excluded items instead of removing the action.

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

* feat(forks): surface hidden-item counts by kind + admin path list

WIP: expose items dropped by the visibility filter (hidden_ahead/hidden_behind
in the compare response): by-kind counts for everyone, kind+path only for admins.

* fix(forks): don't close the deployment request on a partial (hidden-items) deploy

Making the deploy button reachable in the partial-visibility case exposed a bug:
a clean merge-into-parent deploy unconditionally closed any open fork deployment
request as "merged" — marking its comments obsolete and notifying the requester
and assignees of a merge — even when hidden ahead changes were excluded from the
list and left undeployed. Only close the request as merged when the full ahead
set was visible (all_ahead_items_visible); otherwise leave it open (with a toast)
so someone with full access can finish it.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 23:52:34 +02:00
Ruben Fiszel 76a9523009 feat: use derived username instead of email for non-member superadmins (#9857)
* feat: use derived username instead of email for non-member superadmins

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

* fix: address review - drop redundant username cache, guard whoami membership by email

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

* refactor: use explicit non_member boolean instead of role string for superadmin banner

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

* fix: resolve email from password table for non-member superadmin permissioned_as

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

* fix: resolve non-member superadmin drafts via shared username->email resolver

Adds resolve_username_to_email (usr, then super_admin password fallback for both derived-username and email modes) and uses it in get_email_from_permissioned_as and the drafts get/list endpoints, so a non-member superadmin's drafts resolve and no email leaks into the drafts payload.

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

* test: superadmin-not-in-workspace schedule uses derived username as permissioned_as

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

* fix: resolve non-member superadmin identity in draft owner-circles, username_to_email, and home filter

Applies the password-fallback username resolution to the script/flow/app/draft owner-circle subqueries and the username_to_email endpoint (was an admins-workspace 'username == email' hack), and switches the home items-list user-folder filter to the non_member flag instead of the now-broken username-contains-@ heuristic.

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

* fix: backfill non-member superadmin favorites from email to derived username

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

* fix: propagate DB errors in username resolution instead of leaking email (CI review)

Addresses cubic-dev-ai P2: get_instance_username_or_fallback_to_email now returns Result and only falls back to the email for a genuine 'no derived username'; a query error propagates so callers fail closed rather than leaking the raw email as the acting username.

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

* fix: clarify non-member superadmin popover (username used + admin permissions)

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

* fix: keep username_to_email endpoint member-only to not disclose non-member superadmin email (CI review)

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

* fix: forbid disabling automate_username_creation once usernames assigned (CI review)

Makes the setting effectively one-way once instance-wide usernames exist, so the global-uniqueness invariant that keeps stored u/<username> identities (schedules/triggers/drafts/superadmin ownership) unambiguous can never be dropped back to workspace-local uniqueness. Re-saving false on an already-disabled instance stays a no-op.

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-01 14:54:07 +00:00
Ruben Fiszel cfcc0b9453 chore(main): release 1.744.0 (#9839)
* chore(main): release 1.744.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-01 11:47:34 +02:00