mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 00:02:19 +00:00
dependabot/docker/node-26-alpine
13341 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0c42a28353 |
chore(deps): bump node from 24-alpine to 26-alpine
Bumps node from 24-alpine to 26-alpine. --- updated-dependencies: - dependency-name: node dependency-version: 26-alpine dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
7031744a19 |
fix(nsjail): precompile python stdlib + raise download rlimit_as (#9429)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
3b2e748daf |
feat(frontend): add rebuild dependency map button to workspace settings (#9424)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
7edf3f0212 |
fix(auth): filter script/flow listings by token scope (GHSA-2ppx-66jv-wpw5) (#9426)
A token scoped to a single script or flow path (e.g. `scripts:read:f/allowed/*`) could call `GET .../scripts/list_search` (or `/list`) and receive `path` + full `content` for every script the underlying user could see — likewise `flows/list_search` leaked the full flow `value`. Route-level scope checks only validate `domain:action`, and the listing handlers did no per-row scope filtering, leaking out-of-scope source/definitions to narrowly-scoped tokens. Apply `build_scope_path_predicate` (added in #9302 for resources/variables) to `list_search_scripts`, `list_scripts`, `list_search_flows`, and `list_flows`, mirroring the resources/variables fix exactly. Unscoped tokens and tokens whose only scopes are `if_jobs:filter_tags:*` are unaffected. Adds integration regression tests (scripts + flows) covering: path-scoped token sees only in-scope paths, broad `*:read` token still sees all RLS-visible items, tag-filter-only and unscoped tokens unchanged. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
89a7a37776 |
fix(backend): authorize single-job read endpoints by job/flow visibility (#9416)
* fix(backend): authorize single-job read endpoints by job/flow visibility Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(jobs): share read links + cached access checks for run visibility - Cache the job read-access RLS probe (size-bounded LRU keyed by the caller's authz-relevant identity + job id; no TTL since job-side inputs are immutable). - Inherit visibility along the full parent_job chain so any flow you can see lets you read its (deeply nested) steps. - Share read links: GET /jobs/job_view_token/{id} mints a stateless HMAC(workspace_key, job_id) token (only if the caller can read the job); the token grants an authenticated member read of that job and its flow subtree via a ?view_token query param or X-View-Token header. Run page gains a Share button and honors a ?view_token link. - Denied-but-existing reads now return 403 with guidance to request a share link (vs 404 for non-existent), and the run page renders that case with instructions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(jobs): address PR review — scope-tag check on mint, constant-time view-token verify - P1 (Codex): get_job_view_token now enforces the caller's if_jobs:filter_tags scope before minting, so a tag-scoped token can't mint a transferable link for a job outside its tags. Adds a scoped-token regression test (allowed + denied). - Constant-time view-token verification (HmacSha256::verify_slice) instead of comparing hex strings (Claude/Pi nit). - get_completed_job_result: an authed reader passing an invalid suspended-secret triple now falls through to the normal visibility gate instead of erroring out (Claude nit); unauthenticated callers still rejected. - Length-prefix the read-access cache key fields so no input values can collide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(api): add job_view_token to openapi spec; use generated client in run page Addresses Codex review nit: the new GET /jobs/job_view_token/{id} endpoint was missing from openapi.yaml (the source the frontend client is generated from). Adds the path + operationId getJobViewToken, and switches the run page's Share button from a raw fetch to JobService.getJobViewToken. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): carry view_token on share-link downloads Addresses Codex review: download actions bypass the request interceptor that adds X-View-Token (downloadViaClient uses raw fetch; cookie-mode downloads use plain hrefs), so a share-link viewer got 403 downloading logs/results/args. Append the view_token query param to the job download paths (result/logs/args/flow-all-logs) via a new appendViewToken() helper, covering both client-fetch and href modes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(jobs): enforce tag scope in require_job_read_access (view-token use side) Addresses Codex P1: the view_token use-side bypassed if_jobs:filter_tags on handlers that don't tag-filter their data query (result_by_id, get_flow_job_debug_info, get_otel_traces) — a tag-scoped token could use someone else's valid share token to read out-of-scope job data. Move the tag-scope check into require_job_read_access (runs before any created_by/view_token/RLS grant), so it applies uniformly to every gated handler; removes the now-redundant explicit check in get_job_view_token. Adds a use-side regression test (scoped token + valid out-of-scope view_token denied on otel/result_by_id; in-scope still allowed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): include workspace in share read link Addresses Codex P1: the copied share URL omitted the workspace. The token is signed with the run's workspace key and the logged layout only switches $workspaceStore when the URL carries workspace=, so a recipient whose persisted active workspace differs would open the link against the wrong workspace and the token would fail validation. Pin workspace= alongside view_token in the link. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(jobs): authorize get_result_maybe get_started branch for queued jobs Addresses Codex P1: get_completed_job_result_maybe only gated when a completed row existed; with ?get_started=true a non-reader reached the fallback branch and got started:true for a running private job. Now fetches created_by and authorizes (created_by/view_token/RLS, or anonymous for unauth) before disclosing running-state; a non-existent job still returns started:false (leaks nothing). Adds a regression test with a queued (no completed row) private job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
fefa8e438d |
chore(docker): use nsjail runtime packages instead of dev packages (#9419)
Swap the final-stage nsjail dependencies (libprotobuf-dev, libnl-route-3-dev) for their runtime-only counterparts (libprotobuf32, libnl-route-3-200, libnl-3-200) across the root Dockerfile, DockerfileSlim, and DockerfileSlimEe. nsjail is already compiled in the build stage, so the final image only needs the runtime shared libraries. This shrinks the images and reduces CVE scan noise from unused dev packages. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
00cd89fff3 |
chore(main): release 1.714.1 (#9408)
* chore(main): release 1.714.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.714.1 |
||
|
|
2bff250f89 |
feat(frontend): harmonize diff button placement in script and raw app editors (#9410)
* feat(frontend): harmonize diff button placement across editors Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(frontend): address review nits — drop unused diffDrawer param, fix stale comments Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ab2a15b2a8 |
fix(triggers): prevent Zoom challenge handler from being used as a signing oracle (#9413)
The Zoom URL-validation challenge handler in `handle_challenge_request`
would HMAC-sign any arbitrary `plainToken` and return the result. Since
Zoom webhook verification checks `HMAC-SHA256(secret, "v0:{ts}:{body}")`,
an attacker could craft a `plainToken` in that format to obtain a valid
signature for a forged body, bypassing authentication on a later request.
Unlike the Twitch handler, the Zoom handler verifies no signature on the
challenge request (Zoom's protocol does not include one). Reject any
`plainToken` containing `:` or longer than 128 chars: legitimate Zoom
validation tokens are short random hex strings that never contain colons,
while the exploit requires the colon-bearing `v0:{ts}:{body}` format.
Fixes WIN-2008
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
9e6559a6f6 |
fix(nsjail): raise python download fd limit for --compile-bytecode (WIN-2009) (#9414)
#9393 added `--compile-bytecode` to the uv pip install run inside the python download nsjail. uv spawns a Python interpreter that compiles .py files with parallelism scaling to the host CPU count, opening many file descriptors at once. The download nsjail capped `rlimit_nofile` at 64, which is exhausted on high-core machines, failing every install with "Failed to bytecode-compile ... Too many open files (os error 24)". Low-core VMs never hit the cap, so this surfaced only as a regression on larger workers after upgrading. Raise `rlimit_nofile` to 10000, matching the runtime configs (run.python3 / run.ansible) that already use that value. Fixes WIN-2009 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
73edebc833 |
fix(backend): route //native TypeScript previews to native workers (WIN-2007) (#9407)
* fix(backend): route //native TypeScript previews to native workers Previewing a TypeScript script carrying the `//native` annotation was pushed with `language = bun` (what the editor sends), so the job was tagged `bun` and routed to a regular bun worker. A native-mode worker neither matches the `bun` tag nor accepts a non-native `script_lang` (worker.rs rejects with "cannot execute non-native job with language 'bun'"), so previewing a `//native` script on a native-only worker setup failed — even though the deployed version of the same script runs fine as `bunnative` / tag `nativets`. `push` now reconciles the preview language with the `//native` annotation for `JobPayload::Code`, mirroring the deploy-time logic in `worker_lockfiles`: `bun` + `//native` is promoted to `bunnative` (tag `nativets`), and `bunnative` without `//native` is demoted back to `bun`. This makes a preview run exactly like the deployed script would, and covers every preview entry point (run_preview_script, inline preview, codebase preview) since they all go through `JobPayload::Code`. Adds regression tests asserting the queued job's `script_lang`/`tag` for all four (declared language × annotation) combinations. Fixes WIN-2007 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(backend): add sqlx cache for preview_native_tag test query The regression test's `sqlx::query!` for `v2_job` (tag, script_lang) needs a cached entry so `SQLX_OFFLINE=true` CI compiles it. Adds exactly one new cache file; no existing (OSS or EE) caches removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(backend): trim preview native-tag tests to the essentials Keep the core regression (bun + //native → bunnative/nativets) and the guard that plain bun previews are unaffected. Drop the two bunnative- declared cases, which only re-verified the mirrored demote logic and weren't the reported issue. The shared query is unchanged, so the sqlx cache stays valid. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2ac198396e |
chore(main): release 1.714.0 (#9390)
* chore(main): release 1.714.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.714.0 |
||
|
|
8ad699d27b |
Refresh slim image runtime packages (#9396)
* Refresh slim runtime packages * fix(docker): bump pre-baked python to 3.12.12, drop redundant pip/setuptools upgrade Align the slim images' pre-baked uv-managed Python with the backend default (PyVAlias::Py312), which previously requested 3.12 while the image baked 3.11.10 — a minor mismatch that made the pre-bake unusable (every default job re-downloaded 3.12 at runtime). Pinning 3.12.12 (latest 3.12 in uv's list) also drops bundled setuptools entirely and ships current pip via python-build-standalone, so the explicit `uv pip install --upgrade pip setuptools` step is now redundant and removed. Also remove the dead PYTHON_IMAGE ARG from RHEL8/RHEL9 Dockerfiles (declared but never referenced in any FROM stage). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
24e3ef27be |
fix(cli): stop git-sync promotion deploys from dropping triggers/schedules (#9403)
* fix(cli): stop git-sync promotion deploys from dropping triggers/schedules Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: bump git-sync hub script to hub/28261 (windmill-cli 1.713.2) Points LATEST_GIT_SYNC_SCRIPT_PATH at the republished sync-script-to-git-repo that pins windmill-cli@1.713.2, which carries the promotion include-derivation fix in this PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
30057445f9 |
avoid crypto.randomUUID in WorkspaceItemDrillPicker (#9405)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e356bb1f5d |
fix(cli): make encryption key push non-interactive-safe + add --skip-reencrypt-on-key-change (#9402)
When encryption_key.yaml changes and is pushed via `wmill sync push`, pushWorkspaceKey prompted interactively to confirm re-encrypting the remote secrets with the new key. That prompt ignored `--yes` and had no TTY guard, so a CI/non-interactive push that included the key would block (or behave undefinedly) on the prompt. Thread a key-push options object (non-interactive flag + explicit re-encryption choice) through pushObj into pushWorkspaceKey: - Non-interactive (`--yes` or no TTY) and no explicit choice: skip the prompt and default to re-encrypting all remote secrets with the new key (matches the interactive default), preserving their plaintext values. - New `--skip-reencrypt-on-key-change` flag (and the WMILL_NO_REENCRYPT_ON_KEY_CHANGE=true env var for CI) opt out of re-encryption — only safe when the remote ciphertexts are already encrypted with the new key (e.g. workspace/instance migration). - Interactive behavior (TTY, no `--yes`) is unchanged. Regenerates system_prompts for the new option and adds unit tests for the no-op, re-encrypt-by-default, flag-skip, and env-skip paths. Fixes WIN-2005 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d71d553ba4 |
Windows build broken by #[cfg] on tokio::select! branch (#9404)
#9400 (WIN-2003) added the ctrl_break() handler as a `#[cfg(windows)]` branch inside the two Windows-path `tokio::select!` blocks in shutdown_signal. tokio's `select!` macro does not accept `#[cfg(...)]` attributes on individual branches, so windmill-common fails to compile on Windows ("no rules expected this token in macro call"). This slipped through CI because the only job that builds the backend on Windows is cli-tests.yml's `test-windows`, which triggers only on `cli/**` changes — #9400 was backend-only. Fix: define `ctrl_break()` for the whole `not(any(linux, macos))` scope instead of just `windows`. On Windows it awaits the real CTRL_BREAK signal; on other non-unix targets it is a never-resolving future, so the branch is inert there. The select! branches become plain (no per-branch `#[cfg]`), which the macro accepts. Verified: the `#[cfg]`-on-branch form reproduces the exact macro error against tokio 1.46.1, and the fixed form compiles clean. Fixes WIN-2003 (Windows build regression) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e8ad53dae9 |
fix: resolve username rename failing on apps with runnable deps (#9401)
The instance username-conflict resolver rewrote workspace_runnable_dependencies.app_path to the new user path before the app row itself was renamed, violating fk_workspace_runnable_dependencies_app_path. That FK is ON UPDATE CASCADE, so renaming the app already propagates the new path; the manual rewrite was redundant and mis-ordered. Any user owning an app under u/<username>/ with a tracked runnable dependency hit HTTP 500 and could not have their username conflict resolved. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2e1445616a |
feat: handle CTRL_BREAK_EVENT for graceful shutdown on Windows (#9400)
On Windows, shutdown_signal only registered ctrl_c() (CTRL_C_EVENT). CTRL_BREAK_EVENT — the default kill signal sent by Nomad's raw_exec driver on Windows — had no handler, so the worker terminated immediately without graceful shutdown, interrupting running jobs. Add a ctrl_break() helper (mirroring the Unix terminate() helper) and register it as an additional branch in both Windows tokio::select! blocks in shutdown_signal. Fixes WIN-2003 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
de76668c10 |
fix(frontend): align Monaco editor font size with text-xs (#9161)
* fix(frontend): align Monaco editor font size with text-xs across viewports * fix(frontend): make placeholder lineHeight reactive to fontSize * fix(frontend): align GraphQL schema viewer font size with text-xs The read-only GraphQL schema viewer was the lone Monaco instance still inheriting Monaco's 14px default. Wire it through editorFontSize like the other editors so it stays in sync with text-xs across viewports. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
ba0e4c8280 |
oauth: add salesforce provider (#9380)
* oauth: add salesforce provider Register Salesforce OAuth (Authorization Code) for Windmill resource connect. Production uses login.salesforce.com; the sandbox block points at test.salesforce.com (URL overrides only; scopes inherited) per #9358, so a single canonical `salesforce` resource type covers both with separate `salesforce_sandbox` instance credentials. Paired with the hub integration: windmill-labs/windmill-integrations#131. The Salesforce icon already exists in the frontend (SalesforceIcon.svelte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix JSON syntax error in oauth_connect.json * fix: add salesforce production tile to OAuth settings dropdown --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1275487f02 |
feat: refine ask-user-question chat display and keyboard nav (#9392)
* feat: refine ask-user-question chat display and keyboard nav Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style: use text-accent for ask-user-question icon Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: focus active choice when clicking ask-user-question card Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: disable chat input while an ask-user-question is pending Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: focus active choice on card click instead of pointerdown Preserves text selection on the question card; wired as a use: action so the non-interactive card needs no keyboard handler. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: extract isActiveUserQuestion shared predicate Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: cover isActiveUserQuestion predicate Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
943ef6eb20 |
feat: add workspace datatable tools to global AI chat mode (#9395)
* feat: add workspace datatable tools to global AI chat mode Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: cover global-mode datatable tools pure logic Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: expose datatable SQL SDK reference via get_instructions in global mode Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: make datatable get_instructions language-aware, default TypeScript Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: drop datatable/whitelist args from global init_app tool Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: flag missing datatable config as an explicit blocking error in global mode Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: drop dead branch in exec_datatable_sql result handling Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c19441bc8c |
perf(python): add --compile-bytecode to uv pip install (#9393)
Python jobs under nsjail experience slow imports (~465ms for `import requests`) because dependency directories are mounted read-only. Without pre-compiled `.pyc` files, Python recompiles `.py` source to bytecode in-memory on every import in every fresh nsjail process, paying the cost repeatedly. Add `--compile-bytecode` to both `uv pip install` invocations (the Rust-driven install in python_executor.rs and the nsjail download_deps.py.sh script) so `.pyc` files are generated at install time and available at runtime even through read-only mounts. The files are included in both the local cache and S3 piptar uploads. The flag is supported by the uv version (0.9.24+) shipped in the Dockerfile. The existing `__pycache__` skip only filters top-level dirs for dedup logic, not subdirs within packages, so there is no conflict. Fixes WIN-2001 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5c20d6b4f7 |
feat: add global ai chat test tools (#9391)
* feat: add global ai chat test tools
* fix: avoid session id in flow test preview
* test: cover global flow preview ids
* test: require script and flow test tools
* fix: harden global flow test fallback
* Revert "fix: harden global flow test fallback"
This reverts commit
|
||
|
|
075faabf3b |
feat(frontend): surface local drafts in drawer editors with an unsaved-changes banner (#9335)
* feat(frontend): surface local drafts in drawer editors with an unsaved-changes banner Drawer-based editors (the 11 trigger types, plus resource and variable) restore unsaved edits from browser localStorage on open using the same mechanism as flows/scripts, but only showed a transient "Reset to deployed" toast with no way to review the diff. Add a persistent "You have unsaved changes" banner below the drawer header with Show diff / Discard actions, shown whenever the form diverges from the deployed baseline. Replaces the toast for these editors; flows/scripts/apps (full-page) keep their existing toast. - new shared LocalDraftBanner.svelte (Alert-styled bar + DiffDrawer) - DrawerContent: optional `banner` snippet rendered below the header - useTriggerDraftSync: reactive `hasDraft`, `deployed`/`current` getters and `resetToDeployed`; drop the restore toast (banner supersedes it) - wire the banner into all 11 trigger editors + variable; resource lifts its dirty state up to ResourceEditorDrawer via a callback + accessors - fix ScheduleEditorInner.openNew not resetting initialConfig (reused editor instance kept a stale baseline, wrongly flagging a new schedule dirty) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(frontend): address PR review on local-draft drawer banners - LocalDraftBanner: snapshot diff sides at click time so the diff drawer doesn't keep updating as the user types behind it. - VariableEditor / ResourceEditor: scope the banner and its Discard action to the selected workspace; the cross-workspace dirty state stays surfaced by the existing otherDirty Alert. Forward can_write via a new onCanWriteChange callback so the resource banner hides Discard in read-only mode (matching the trigger editors). - useTriggerDraftSync: drop the now-unused path arg from maybeRestore and update all 11 trigger editor call sites. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(frontend): deep-clone fallback in UserDraft.discard to avoid baseline aliasing When a caller passed a live $state proxy as `fallback` (Variable/Resource editors handed `initialStates[selected]` to the banner's Discard), the handle's draft cell ended up sharing the same proxy as the caller's baseline. Subsequent form edits mutated both sides in lock-step and the dirty check kept reporting equal, so the banner never reappeared and the Update button stayed disabled until the drawer was reopened. Cloning the fallback inside `discard` (via `snapshotDraftValue`) gives the handle a fresh tree and decouples the two reactive graphs. Trigger editors already cloned at their call site (resetToDeployed); this just makes the API self-contained for all callers. Also switch the variable form's "Audit log for each access" alert from warning to info — it's informational, not a warning. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(frontend): honor disabled prop in LocalDraftBanner's diff drawer The banner's `disabled` prop hid the inline Discard button but the diff drawer's "Discard changes" action was still wired unconditionally, so a read-only user could bypass the hidden inline action via Show diff. Gate the diff-drawer button on the same flag so both surfaces agree. Flagged by cubic and Codex on PR #9335. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
e4213c1ab8 |
feat(flow-ai): constrain flow-group colors to the NoteColor palette (#9343)
The flow AI chat's set_flow_json tool lets the model set a `color` on each semantic flow group, but nothing told it which colors are valid, so it would sometimes emit hex codes / arbitrary CSS color names. Those render with default styling at best and break the group color picker at worst. - core.ts: the set_flow_json schema `.describe()` and the `groups` system-prompt bullet now spell out that `color` MUST be one of the palette names (yellow, blue, green, purple, pink, orange, red, cyan, lime, gray) — no hex, no CSS colors — and that omitting it lets the editor auto-assign one. - helperUtils.ts: validateFlowGroups now rejects any color outside that palette, sourced from the NoteColor enum so the two can't drift. - helperUtils.test.ts: tests for reject-unknown / accept-known / accept-omitted. Split out of the sessions branch (gl/layout-ai), where it had been bundled into the large feature commit; it's an independent flow-AI improvement. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
eadeac248b |
feat: sessions page with isolated AI chat + flow editor (#9034)
* feat(sessions): chat + editor side-by-side with multi-session state
Introduces the Sessions feature: a workspace where the AI chat and an
editor (flow / script / app / raw-app) sit side-by-side, with each session
having its own AIChatManager instance, history, and target item. Sessions
are persisted across reloads and can be staged into forks for review.
Key pieces:
- sessions/ — SessionWrapper (the split-pane shell), SessionPicker
(sidebar list), SessionForkBar, SessionWorkspaceBar, FlowEditorView /
ScriptEditorView / AppEditorView / RawAppEditorView, ForkDiffDrawer,
sessionRuntime (per-session AIChatManager + draft state),
sessionState (in-memory + persisted index), sessionUnread, sessionScope,
appDraftCodec / flowDraftCodec, forkEditUrl, /sessions route.
- WorkspaceItemDrillPicker refactor — extracts WorkspaceItemRow + adds
surfaceAI drafts, stale-while-revalidate. workspacePicker.ts drops
explicit invalidate() in favor of always re-fetching in the background.
- ForkDiffDrawer + WorkspaceItemDiffViewer — per-kind diff bodies
reusable from the compare page. FlowGraphDiffViewer / FlowGraphV2 gain
inlineDiff forwarding + onHeight callback for equal-height layout.
- Global AI chat sessions plumbing — AIChatManager exports the class +
adds disabledModes, beforeSend hook, scoped instance context. AIChat /
AIChatDisplay accept session-only props (wideLayout, emptyHint,
inputPreface, hideHeader, hideModeSelector, forceDisabled). Chat
preserved across /flows/add → /flows/edit, /scripts/add → /scripts/edit.
- Draft-first loaders — sessions open drafts when present, otherwise
seed a draft from the last deployed value via globalDraftStore.
RawAppEditor / AppEditor / AppEditorHeaderDeploy get newApp prop +
fixes so draft-only apps can deploy.
- Compare page (/forks/compare) — bigger overhaul to plug into the new
drawer.
- Sidebar — Sessions entry + unread badge + status dot in
SidebarContent / MenuButton / SideBarNotification.
- Misc fixes — chat group color palette constraint, deploy_workspace_item
confirmation dropped, open_preview tool, picker drafts surfacing,
fork archive/delete buttons on compare page.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): bypass UserDraft inside session panes + sessionUnread crash
After merging main's UserDraft PR (#9121) into the sessions branch, two
integration issues surfaced:
1. AppEditor.svelte calls `UserDraft.use<App>('app', path)` at the
component level — keyed by ($workspaceStore, 'app', path). Sessions
that haven't materialized a fork yet stay at the user's main
workspace, so a session targeting an app at the same path as a
regular /apps/edit tab shared the same LS key. The session would
read the regular tab's autosave and write its fork-edits back over
it.
Gate UserDraft.use on `!getContext('aiChatManager')` — sessions
inject the manager via setContext, so inside a session pane the
handle is `undefined`, stateApp falls through to the `app` prop
the session loaded, and the auto-save $effect bails. Same gate on
the four UserDraft.remove call sites in AppEditorHeader and
RawAppEditorHeader so save/deploy from a session pane doesn't wipe
the LS draft of a non-session tab at the same path.
2. sessionUnread.svelte.ts called useLocalStorageValue at module
scope. Main's PR added a deep-mutation $effect inside that helper,
which now requires component-initialization context — every page
crashed at import time with `Svelte error: effect_orphan`.
Replaced with a plain module-level $state + manual localStorage
persist; same reactivity contract for callers.
3. ScriptEditorView.svelte was passing a `replaceStateFn` prop that
ScriptBuilder dropped on main. Removed.
Verified end-to-end with Playwright:
- /flows/edit/{path} regression: UserDraft handle still created, no
console errors
- /sessions loads, sessionUnread doesn't crash
- Session targeting non-raw app `u/admin/userdraft_collision_test`
displays the fork content (FORK_ONLY_MARKER) even with an LS
poison at `userdraft/w/local/app/{path}` containing a
POISONED_BY_REGULAR_TAB_AUTOSAVE marker; poison remains untouched
after the session loads and renders
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): stop fork-create retry loop on first user message
Removed the SessionWrapper $effect that retroactively committed the
session's workspace from the in-memory chat history. When opening a
session whose previous commit attempt had failed (or whose response was
lost) the effect ran in a tight retry loop, flooding the user with
`workspace_pkey` violations from `create_workspace_fork`.
The send path already commits through `AIChatManager.beforeSend` →
`commitSessionWorkspace`, which is the deterministic moment-of-action.
The $effect was a redundant reactive bridge that turned every backend
failure into an infinite retry.
Also hardens `materializeFork`/`commitSessionWorkspace` so the most
common cause of the duplicate-key error self-heals:
- `materializeFork` short-circuits when `fork.id` is already in
`$userWorkspaces` (the previous create actually succeeded, we just
lost the response). On a `workspace_pkey` catch, refresh the workspace
list and adopt the existing row instead of toasting an error.
- On a real `materializeFork` failure, `commitSessionWorkspace` now
drops `pending_fork` so the session falls through to the
workspace-pick fallback instead of looping on the same broken intent.
* feat(sessions): show EditorHeader breadcrumb in the not-found state
When a session's target item has been deleted or moved, the editor pane
used to render a bare "Script not found at path X" line — leaving the
user with no way to navigate to a different target without backing out
of the session.
Each editor view now renders a `SessionItemNotFound` shell instead: a
real `EditorHeader` (read-only summary, no pen popover) with a
breadcrumb keyed to the missing kind+path, plus the "not found" copy
below. Clicking any breadcrumb segment opens the workspace picker
scoped to that level — pick a replacement and the session swaps target
via the existing `onNavigate` callback.
`SessionItemNotFound` maps `raw_app` to `EditorHeader`'s `kind: 'app'
+ raw_app: true` so the picker routes through `/apps_raw/...`; the
local label still says "Raw app not found" (not "App not found") so
the user knows which surface is missing.
* fix(picker): stop self-feeding fetch effect that OOM'd the tab
The drill picker's $effect watched `scope` and called `ensureLoaded`
on every change. `ensureLoaded` reads `loaded[kind]` synchronously
(to decide whether to show a spinner), so the effect ended up
subscribed to the very signal it fills. Each fetch result wrote
`loaded[kind] = items`; Svelte 5's $state proxy notifies on every
property set even when the reference is unchanged from cache, which
refired the effect, which called `ensureLoaded` again, which awaited
the cached fetch, which wrote `loaded[kind]` again... runaway loop.
In `/scripts/edit/...` the picker's lifecycle stabilised quickly
enough to mask the loop, but in a session pane (multiple warm
sessions, picker kept alive by the surrounding state) the cycle
spun freely — 29.8 million iterations in <100 ms during testing,
enough to OOM Firefox / kill the Chromium tab.
Two changes:
- Replace the scope-watching $effect with an explicit `setScope()`
helper called from `drill()`, `goUp()`, and `onMount`. Fetch is
now a callback reaction to user navigation, never a reactive
consequence of one. No closed feedback cycle is possible.
- Untrack the `loaded[kind]` read inside `ensureLoaded`. The search
$effect (which loads every kind on first keystroke) is still a
reactive caller; the untrack stops it from subscribing to the
signal `ensureLoaded` fills, so the same loop can't form there.
* feat(script-editor): wire initialTestPanelCollapsed through ScriptBuilder
The `initialTestPanelCollapsed` prop was already declared on
`ScriptBuilderProps` (used by the session preview to start the editor
with the run/test pane closed) but never destructured in
`ScriptBuilder.svelte`, so the value silently dropped on the floor
and the test pane always opened.
- `ScriptBuilder.svelte` — destructure the prop and forward it to
`<ScriptEditor>`.
- `ScriptEditor.svelte` — accept the prop and seed `rawTestPanelSize`
to 0 when true, while keeping `storedTestPanelSize` at the default
30 so the user's first toggle expands the pane to a sensible width
rather than 0.
Regular `/scripts/edit/...` doesn't pass the prop → default `false`
→ panel still opens by default.
* fix(sessions): resolve aiChatManager via context in AskUserQuestionDisplay
Inside a session the chat uses a per-pane AIChatManager injected via context. AskUserQuestionDisplay imported the global singleton, so answers clicked in a session dispatched to the singleton's callback map and the AI loop stalled. Resolve via getContext with singleton fallback, matching ChatMode / ToolExecutionDisplay.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(raw_apps): let preview start in single-view on the preview tab
Add a defaultSplitWithPreview prop (default true). When false (session preview), the editor boots in single view with the preview tab selected: gate the onMount default-file activation, the setActiveDocument auto-activation, and iframeShouldMount so the UI Builder bundler iframe still mounts when preview is the active tab. RawAppEditorView passes defaultSplitWithPreview={false}.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(copilot): add get_preview_status tool and make open_preview idempotent
So the assistant can tell whether the session preview already shows the item it just edited, instead of re-opening or re-offering it. Mirrors the open_preview handler plumbing (setGetPreviewStatusHandler) and the session runtime registers it alongside open_preview. open_preview now returns 'already open' when the requested target matches the active session's current target. The system prompt steers the AI to check status before offering. Unit tests cover the no-arg schema, the session-only error, and handler dispatch.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): make script preview reactive to AI draft writes
ScriptEditorView read the draft via static UserDraft.get inside an effect, which only subscribes to UserDraft's reactive cell when a live entry exists. None did for the preview path, so the chat's writes (UserDraft.save) only touched localStorage and the open preview never updated. Hold a live handle via UserDraft.useMany (reactive getter so it re-acquires when open_preview swaps the path without remounting) and read inbound through handle.draft, materializing the shared $state cell that bridges the chat's writes to the editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): make raw-app preview reactive to AI draft writes
Mirror of the script-preview fix. RawAppEditorView read the draft via static UserDraft.get inside an effect, which only subscribes to UserDraft's reactive cell when a live entry exists. None did for the preview path, so the chat's raw-app writes (UserDraft.save / setDraftAndMeta, from write_app_file / patch_app_file / write_app_runnable) only touched localStorage and the open preview never updated. Hold a live handle via UserDraft.useMany (reactive getter so it re-acquires when open_preview swaps the path without remounting) and read inbound through handle.draft. Verified in-browser: an external UserDraft.save live-updates the bound summary in the open preview.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): make flow preview reactive to AI draft writes
Mirror of the script/raw-app preview fixes, completing two-way binding for all three session editor kinds. FlowEditorView read the draft via static UserDraft.get inside an effect, which only subscribes to UserDraft's reactive cell when a live entry exists — none did, so the chat's writes (write_flow / patch_flow_json / set_flow_module_code) only touched localStorage and the open preview never updated. Hold a live handle via UserDraft.useMany (reactive getter so it re-acquires when open_preview swaps the path without remounting) and read inbound through handle.draft. Verified in-browser both directions: an external UserDraft.save live-updates the flow header summary and rebuilds the module graph; a preview edit propagates through the debounced save to both UserDraft.get and the chat's getGlobalDraft adapter.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(sessions): surface local-storage drafts in fork diff & compare page
Augments the backend fork-vs-parent comparison with browser-local (UserDraft) drafts so a session's uncommitted AI/user changes are visible in the Fork Diff Viewer and the /forks/compare page. Adds forkDraftDiff.ts (augmentForkComparisonWithLocalDrafts + getForkItemValue), a 'local changes detected' / new-draft warning surface (checkbox-slot warning icon, no-op-baseline filtering, dedup), a 'Local draft <> fork' tab in DiffDrawer, and selectTooltip/nonSelectableTooltip plumbing in Row/WorkspaceDeployLayout.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Revert "feat(sessions): surface local-storage drafts in fork diff & compare page"
This reverts commit
|
||
|
|
32b4771f19 |
chore(main): release 1.713.1 (#9389)
* chore(main): release 1.713.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.713.1 |
||
|
|
9d9c5038ce |
fix(api): handle multi-version scripts when removing granular ACL (#9388)
* fix(api): handle multi-version scripts when removing granular ACL
remove_granular_acl built a CTE whose `old` subquery selects one row per
matching table row, then read it back via the scalar subquery
`(SELECT old_write FROM old)` in the RETURNING clause. For the `script`
table the PK is (workspace_id, hash), so a path with multiple deployed
versions yields several rows sharing the same (workspace_id, path). When
two or more versions carried the ACL key, `old` returned multiple rows and
PostgreSQL rejected the scalar subquery with "more than one row returned by
a subquery used as an expression", making it impossible to remove an ACL
entry from a script's permissions panel.
All versions share the same extra_perms value (the UPDATE applies to every
matching row), so any single row's old_write is representative. Add
`LIMIT 1` to the scalar subquery. Other kinds are unaffected because they
have a unique constraint on (workspace_id, path/name).
Introduced by
|
||
|
|
b16828d480 |
chore(main): release 1.713.0 (#9369)
* chore(main): release 1.713.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.713.0 |
||
|
|
edf340c4d4 |
fix(security): re-pin cached hub scripts to CVE-patched versions (+ HUB_BASE_URL override for cache mode) (#9387)
* feat(cache): allow overriding hub base url via env in `cache` mode The `windmill cache hubPaths.json` prebuild step (run in the Dockerfile) never connects to the DB, so HUB_BASE_URL stays at its compiled default (https://hub.windmill.dev) — unlike server/worker modes which load it from the DB global setting. This made it impossible to point the prebuild cache step at a private or staging hub. Read HUB_BASE_URL from the environment at the start of cache_hub_scripts and store it into the existing HUB_BASE_URL ArcSwap (the same static the hub fetch functions read). No effect unless the env var is set and non-empty; server and worker modes are unchanged (they still use the DB setting). This also enables validating hub-script dependency changes end-to-end against a local fake-hub before pushing to the real hub. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(security): re-pin cached hub scripts to patched versions windmill-integrations#133 was merged and pushed to the hub, minting new versions with regenerated (CVE-free) lockfiles. Bump the hubPaths.json pins so the prebuild cache step (`windmill cache`) fetches the patched lockfiles instead of the old vulnerable ones (the hub serves each version_id immutably, so the old pins keep returning the vulnerable deps until bumped). - slackErrorHandler 19741 -> 28241 - slackRecoveryHandler 9080 -> 28239 - slackSuccessHandler 28220 -> 28240 - smtpReport 9086 -> 28242 - appReport 28076 -> 28243 (puppeteer screenshot script) - gitInitRepo 28219 -> 28229 (already-fixed hub version; pin was stale) Validated end-to-end against the real hub: `windmill cache` with these pins produces a clean cache_nomount/bun (axios 1.16.1, form-data 4.0.5, follow-redirects 1.16.0, nodemailer 8.0.10, ws 8.21.0, svelte 5.55.8, devalue 5.8.1; basic-ftp and ip-address no longer pulled). No vulnerable versions remain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d23d8374dd |
use libgnutls30 in slim images (#9286)
* Harden slim image security surface * Limit slim hardening to libgnutls pin * fix(docker): pin libgnutls30 to exact +deb12u7 in slim images Replace the +deb12u* wildcard with the exact current security build so builds fail loudly when Debian ships a newer patch, prompting an explicit review/bump rather than silently floating forward. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(docker): drop libgnutls30 version pin, keep explicit listing The version pin (exact or wildcard) was not the load-bearing part of this change. Naming libgnutls30 explicitly in apt-get install is what forces apt to upgrade it past the base image's older pre-installed version — transitive deps from wget/curl/git would otherwise leave it in place because their version constraints are already satisfied. Dropping the version specifier so each rebuild picks up the current security build automatically, matching the PR's stated intent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docker): drop libgnutls30 comment Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f0301b1605 |
feat(flows): preserve step/subflow worker tags under a custom-tagged flow (#9375)
* feat(flows): preserve step/subflow worker tags under a custom-tagged flow A flow running on a custom worker tag force-propagates that tag to every descendant step, script and nested sub-flow, overriding their own declared tags. This made it impossible to route a specific step or sub-flow to a different worker group. The new opt-in FlowValue.preserve_step_tags lets a step that declares its own non-empty tag run on it; untagged steps still inherit the flow tag. Defaults off to preserve existing behavior. * chore: regenerate system prompts for preserve_step_tags Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(flows): nest preserve_step_tags toggle under flow worker tag setting The toggle only affects routing when the flow has a custom worker tag, so show it as a sub-setting of the Worker Group tag picker, visible only once a tag is set, instead of as a standalone option. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): allow step worker tag picker when preserve_step_tags is enabled When a flow defines a worker tag, the per-step tag picker was replaced by a read-only "Flow's WG" label. With preserve_step_tags enabled the step's own tag is honored, so the picker must remain editable in that case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): propagate preserve_step_tags to branch and loop bodies payload_from_modules built the synthetic RawFlow for branch/loop bodies with a default FlowValue, dropping preserve_step_tags. Tagged steps inside a branch or loop therefore still inherited the parent flow tag even with the flag enabled. Thread the flag through to the synthetic FlowValue so the behavior is consistent for nested containers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): clear preserve_step_tags when flow worker tag is removed Avoids the flag lingering as invisible state after the flow tag (and its toggle) are removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): repair preserve_step_tags propagation to branch/loop bodies The previous commit added flow.preserve_step_tags at the payload_from_modules call sites but the parameter and FlowValue field were not actually threaded through (a failed edit left the function unchanged), so the crate did not compile. This completes the change: payload_from_modules takes preserve_step_tags and sets it on the synthetic FlowValue for branch/loop bodies. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): complete preserve_step_tags propagation to branch/loop bodies Previous two commits left windmill-worker uncompilable: payload_from_modules received flow.preserve_step_tags at its call sites but the parameter and the synthetic FlowValue field were not actually added. This adds the parameter, sets preserve_step_tags on the synthetic FlowValue, and threads flow.preserve_step_tags through all five call sites. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): clear preserve_step_tags whenever the flow worker tag is removed The flag was only reset when the Worker Group toggle was switched off, not when the tag was cleared directly in the picker (or via the YAML editor), leaving preserve_step_tags=true as invisible state with the advanced badge still reporting it active. Move the cleanup into the reactive block that already tracks the flow tag so every clear path is covered. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2ddf93de96 | fix(auth): enforce monotonic privilege on user token lifecycle endpoints (#9371) | ||
|
|
def01b8ff6 |
fix(frontend): sanitize user markdown to prevent stored XSS (#9386)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
fddbe4a51c |
docs(skills): fix //native marker + import rules for bunnative, remove legacy nativets skill (#9382)
* docs(skills): document mandatory //native marker for bunnative and nativets * docs(skills): clarify windmill-client is the only allowed library in native mode * docs(skills): remove legacy nativets skill in favor of bunnative Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(skills): fix bunnative import rule - any bundleable lib, not just windmill-client Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2c0c2c467f |
fix(apps): make public apps opt into cross-origin isolation via wm_coep (GIT-884) (#9374)
* fix(apps): make public apps opt into cross-origin isolation via wm_coep
Public app pages served at /public/* and custom paths /a/* were not
getting the COEP/COOP/CORP headers, so they were blocked when embedded
as an iframe inside a cross-origin-isolated page (e.g. another raw app,
which sets Cross-Origin-Embedder-Policy: require-corp). A nested
document loaded into a require-corp context must itself set COEP for
the iframe to load.
Rather than applying the isolation headers to all public pages (which
would also force COEP on classic apps and break subresources without
CORP, e.g. external image URLs or embeds), public apps now opt in via
a `wm_coep` query param on the embed URL:
<iframe src="https://<domain>/public/<ws>/<secret>?wm_coep=on">
The app publish drawer gains a URL/Embed toggle: "URL" shows the plain
shareable link (param-free), "Embed" shows a ready-to-copy iframe
snippet with wm_coep baked in, so the flag is discoverable exactly when
embedding and absent otherwise.
`wm_coep` is consumed internally and stripped from the app `query`
context so it doesn't collide with app-defined params. Only params we
own are stripped (an explicit set), not the whole `wm_` prefix.
Fixes GIT-884
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* nit
* nit
* fix(apps): only bake wm_coep into embed snippet for raw apps
AppEditorHeaderDeploy is shared by the classic (AppEditorHeader) and raw
(RawAppEditorHeader) deploy drawers. The embed snippet unconditionally
appended ?wm_coep=on, which for a classic/low-code app forces COEP
require-corp on the document and breaks no-CORP cross-origin subresources
(external <img> in AppImage/AppStatCard/AppNavbar, {@html} embeds in
AppHtml, CDN import() in AppCustomComponent) — the exact regression the
opt-in design avoids.
Add a `rawApp` prop (default false); the raw header passes rawApp. The
flag is appended only for raw apps; classic apps get a plain iframe
snippet, and the wm_coep helper text is shown only for raw apps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
f300a716a9 | test: add global chat resource variable schedule evals (#9379) | ||
|
|
b0c3b01d31 |
fix(cli): preserve user drafts on sync push and permissioned-as (#9381)
CLI deploys (sync push, set-permissioned-as) went through the same create/update endpoints as a UI "deploy from draft", which delete the draft at that path. That silently wiped teammates' in-progress drafts on every push. Add a transient skip_draft_deletion deploy flag (mirroring deployment_message) that the CLI sets; the backend then skips the DELETE FROM draft for scripts, flows, and apps. UI deploys are unchanged. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
4b06881918 |
fix(ai): validate token_url for SSRF in OAuth credentials flow (#9385)
get_token_using_oauth resolved the AI OAuth resource's token_url and POSTed to it without any SSRF validation, while base_url is validated in get_base_url. A workspace member with resources:write could point token_url at an internal/metadata address (e.g. 169.254.169.254), turning the server into an authenticated blind SSRF probe. Validate the resolved token_url with validate_url_for_ssrf before the request, gated behind the same ALLOW_PRIVATE_AI_BASE_URLS opt-in as base_url so private AI deployments keep working consistently for both URL fields. ALLOW_PRIVATE_AI_BASE_URLS is now pub so windmill-api can reuse it instead of re-parsing the env var. |
||
|
|
3345837574 | chore: add gpt-5.5 eval model (#9377) | ||
|
|
04a08976ae |
fix: batch encryption-key rotation into one git-sync job (#9355)
* fix: trigger git sync for re-encrypted secrets on encryption key change When changing a workspace encryption key, the secret variables get re-encrypted with the new key, but the git sync was only dispatched for the encryption_key.yaml metadata file. Repos with Secrets sync enabled were left with stale ciphertexts until the next per-variable deployment. Now, after the transaction commits, we also dispatch a Variable git sync event for each re-encrypted secret so the new encrypted values are pushed to the configured repos. Errors are logged but don't roll back the key rotation. Fixes WIN-1994 Fixes #9344 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: batch encryption-key rotation into one git-sync job Workspace encryption key rotation now re-encrypts every secret variable and then dispatches a single batched git-sync job carrying the Key event plus one Variable item per re-encrypted secret. Repos with Secrets sync enabled receive every new ciphertext in one commit instead of nothing (previously only `encryption_key.yaml` was pushed) — and instead of N separate jobs the debouncer might or might not merge. Wires through the new `handle_deployment_metadata_batch` entry point added in the companion EE PR; OSS has a no-op shim so the build stays green. Adds an integration test (`workspace_encryption_key_git_sync`) asserting that rotating the key with 3 secret variables in scope produces exactly one deployment-callback job whose `items` array contains the Key event + all 3 variable entries and `skip_secret=false`. Fixes WIN-1994 Fixes #9344 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump ee-repo-ref for git-sync helper simplification Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: cover non-debouncing git-sync fallback on key rotation Adds a regression test exercising a workspace whose sync script predates hub version 28103: the rotation must still queue a legacy-format deployment-callback job per item (encryption_key + each re-encrypted secret) instead of silently skipping the repo. Bumps ee-repo-ref to the EE fallback fix. Addresses the P1 raised in the PR review (Codex/Pi/Claude): batch path dropped git sync entirely for repos without sync-job debouncing support. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: add sqlx offline cache for encryption-key git-sync test queries The cargo_test CI job builds with SQLX_OFFLINE=true; the two new sqlx::query!/query_as! calls in windmill-api-integration-tests/tests/workspace_encryption_key_git_sync.rs had no cached entries, failing the build with E0282. Regenerated and added only the two new query caches (no EE/feature cache loss). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump ee-repo-ref to updated EE companion PR (08e3b9b) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
96a8eb63d4 |
disable redirect following on AI proxy client to close SSRF (#9370)
* fix(ai): disable redirect following on AI proxy client to close SSRF The AI proxy validates the configured base_url against SSRF rules but the shared HTTP client followed up to 10 redirects without revalidating the hops, so a public base_url could 3xx the server into a private/internal address (e.g. the Docker socket or cloud metadata). Disable redirect following so the validated host is the only one the server connects to. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ai): remove heavy redirect SSRF integration test Drop the integration-test-level regression for redirect following; it spins up a full API server + DB for a one-line client-config change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
bb90f4ce83 |
fix(api): authorize and harden log-file reading endpoints (#9368)
* fix(api): don't follow symlinks when reading service log files Defense in depth on top of the existing `..` path-traversal check in the get_log_file handler: reject the request if the final path component is a symlink, so a planted symlink in the logs directory cannot be used to read arbitrary files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(api): authorize and harden the jobs_u get_log_file endpoint The unauthenticated jobs_u get_log_file endpoint served any job's log file to anyone who knew the job UUID, with no authorization. Gate it the same way as get_job_logs: look up the job (the log directory name is the job id) filtered by workspace and the caller's scope tags, and only allow non-logged-in callers to read logs of jobs created by the anonymous user. Also add defense in depth: refuse to read through a symlink so a planted symlink in the logs directory cannot be used to exfiltrate arbitrary files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
12e06bfa6b |
bump default sync script to hub/28238 (windmill-cli@1.712.0) for fork branch push (#9372)
The fork-branch deployment callback runs the hub script sync-script-to-git-repo-windmill, which imports `windmill-cli` as a pinned npm dependency and runs it in-process (it does NOT shell out to a PATH wmill). hub/28236 pinned windmill-cli@1.706.1, whose `git-deploy --only-create-branch` path returns early without pushing — so the fork branch was checked out locally but never published to the remote. #9366 fixed the CLI and shipped it as windmill-cli@1.712.0, but without a hub-script bump the running callback still used 1.706.1. Bump LATEST_GIT_SYNC_SCRIPT_PATH to hub/28238, which is identical to 28236 except it pins windmill-cli@1.712.0 (content + lockfile). This fixes test_workspace_fork_creates_branch and production fork-branch creation. Also add backend/windmill-common/src/workspaces.rs to the git-sync-test path-gate so future script-path bumps trigger the e2e (the bump alone is not otherwise covered by the gate). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2bf11dcb15 |
feat(oauth): support per-provider sandbox URLs (#9358)
* feat(oauth): support per-provider sandbox URLs in registry + instance settings * fix(oauth): polish sandbox review nits (cc lookup, header label, ee ref) * refactor(oauth): drop dead build_oauth_clients duplicate in windmill-oauth * refactor(oauth): derive sandbox-capable provider list from registry * chore(docker): copy oauth_connect.json into frontend build stage * test(oauth): cover sandbox helpers (as_sandbox, canonical_name, resolve) * chore: update ee-repo-ref to 9297d8f790346e6a6ad540c7bca1a67f91ec11a2 This commit updates the EE repository reference after PR #595 was merged in windmill-ee-private. Previous ee-repo-ref: 3ab3eca9ac15ebab6db991e7964bc5e48ce21f42 New ee-repo-ref: 9297d8f790346e6a6ad540c7bca1a67f91ec11a2 Automated by sync-ee-ref workflow. --------- Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
889101b7f0 |
chore(main): release 1.712.0 (#9340)
* chore(main): release 1.712.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.712.0 |
||
|
|
2553fbfe31 | feat: add deepseek fim support (#9365) | ||
|
|
9a659b636d | fix(frontend): prevent duplicate asset node ids crashing flow graph (#9367) |