mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-21 08:02:26 +00:00
2c1e227d294167b07e357b01c8293c9732c608b7
14099 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2c1e227d29 |
fix: refetch owner lists only on row mutations, not scope changes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UomUzAvrC2cto1T2QUBNnT |
||
|
|
7a2e9aadf1 |
perf: fence non_empty owner subquery in a materialized cte
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UomUzAvrC2cto1T2QUBNnT |
||
|
|
93aab4b57c |
fix: hard-assert sql-interpolated path_prefix, order-independent first_bind, pin subquery in unit tests
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UomUzAvrC2cto1T2QUBNnT |
||
|
|
8a09343975 |
fix: enforce runnable token scopes in non_empty filters, refetch owner lists on mutation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UomUzAvrC2cto1T2QUBNnT |
||
|
|
56d645ec24 |
feat(frontend): hide empty folders/users in home tree view
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UomUzAvrC2cto1T2QUBNnT |
||
|
|
907141152e |
chore(main): release 1.771.1 (#10336)
* chore(main): release 1.771.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.771.1 |
||
|
|
dc5182f86c | fix: operators cannot see flows and apps on the homepage (#10340) | ||
|
|
32c018dc85 | fix: app stepper no longer runs its validation on subgrid focus (#10338) | ||
|
|
023e85bd63 |
fix: open a pipeline step on its code, not its output (#10335)
* fix: open a pipeline step on its code, not its output Clicking a script node in a pipeline replay landed on Output. The code is what the step is, and it is the thing a viewer is usually there to read, so open on it and put the Code toggle first. Recordings made before `codes` existed carry no source, and defaulting them to Code would open an empty pane saying nothing was captured, so the default falls back to Output when the step has no recorded source. The reset is keyed on the selected step, so a tab chosen by hand survives until another step is opened. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: depend the step-tab reset on the selected path alone untrack the codes lookup so the effect tracks only which step is selected. It could not loop either way — it never reads the tab it writes, and the toggle group's programmatic dispatch settles on an identical value — but the dependency set should say what the reset means: reset on a new step, not on a new recording object. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
434c4ac7c8 |
chore: pin ruff to 0.16.0 and keep the python editor rule set stable (#10331)
* chore: pin ruff to 0.16.0 and keep the python editor rule set stable * chore: keep the ruff config path rationale at a single site |
||
|
|
71575bf941 |
chore: remove the unreachable hub raw-app embed proxy (#10332)
The raw-app session recorder replaced the live-iframe demo, and removing `Share as iframe` took the only caller of this proxy with it. Nothing in the frontend, the CLI or the backend can reach `publish_raw_app_embed` any more, so it is an authenticated route kept alive for no consumer. The Hub still stores and renders `external_embed_url` for the raw apps that already carry one, and still exposes its own editors for it; this only drops Windmill's write path, which no longer has a producer. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
3a08656dad |
chore(main): release 1.771.0 (#10316)
* chore(main): release 1.771.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.771.0 |
||
|
|
e80fee86b3 |
feat: record and replay raw app sessions step by step (#10318)
* feat: record and replay raw app sessions step by step * fix: address review findings on raw app session recorder * fix: stamp replay target before pruning the snapshot clone * fix: redact step metadata, lock down replayed frames, fix control pre-state * feat: add a checkpoint timeline to the app recording player * fix: parser-based replay CSP, fold label clicks, drop stale frame indices * fix: scrub redacted attributes, keep scroll, neutralize replay navigation * fix: bound replay payloads, strip namespaced nav links, keep control pre-frames * fix: strip SMIL navigation, redact metadata sources, capture pre-edit on beforeinput * fix: redact template content, drop shadow templates, make replays inert * test: pin snapshot redaction and replay sanitization with DOM tests * fix: allow-list no-record attributes and cover a marked document root * fix: classify input types positively so pickers get pre-change frames * fix: one step per control interaction and bound step metadata * fix: keep button inputs recordable and coalesce only continuous controls * fix: no frames for coalesced repeats and drop inline styles when redacting * fix: fold only the label's own click and keep marked stylesheets out * fix: keep label-forwarded and radio-group pre-frames, fold submitter clicks * fix: bound key pre-frames to their gesture and clear ancestor pointer frames * fix: age-bound pre-frames and treat a radio group as one target * fix: consume pre-frames per interaction and coalesce on the browser repeat flag * fix: spend only the pre-frame a step actually used * fix: settle a step from its successor's pre-state and drop stale pointer frames * fix: bound remote frame payloads and snapshot stylesheets as rendered * fix: let a control change spend its own frame and dedupe Enter activations * fix: record Escape on controls and drop disabled stylesheets * feat: collapse the replay step list by default behind a toggle * fix: neutralize disabled sheets in place and fold Enter submissions * fix: withhold redacted control state, fold key repeats, validate remote metadata * fix: drop noscript markup and fold implicit form submissions * fix: mask a select whose chosen option is redacted * fix: mask redacted select choices before the clone diverges * fix: run clone-paired passes before removals and fold only Enter submissions * feat: record a raw app demo from the publish flow instead of the viewer * fix: wait for in-flight runnable jobs before settling a step * feat: record from the editor menu and replay publicly at /replay * feat: export the app recording player and its loader for the hub * feat: publish from folders only, drop iframe sharing * fix: observe runnable responses where they land and mount the hub recording route * fix: respect the app's sandbox opt-in when recording a session * fix: let stop wait for the runnable the last step is still running * fix: filter redacted class/id to styled tokens and gate publish on admin * fix: drop marked sheets from the token vocabulary and bound the replay error * test: pin the remote app-recording validator * fix: carry in-flight runnables across a reload and fold held keys into one step * fix: bind runnable responses off the request and honor base in the replay handoff * fix: close the settling step when a new fill starts and always re-read stylesheets * fix: empty the no-record marker so it carries nothing of its own * fix: decode css escapes so utility classes survive redaction * fix: read keyDriven from the frame the change starts from * docs: condense recorder comments to the invariant each protects * fix: rewrite only real url() tokens and accept leading css escapes * feat: play flow, script and pipeline recordings on the public /replay page (#10327) * feat: play flow, script and pipeline recordings on the public /replay page * fix: render a recorded approval result inert while replaying * fix: bound an asset sample's cell product and validate recording headers * fix: make a replayed approval step inert and bound nested recording structures * fix: stop recorded markup from fetching and bound flow/script render trees * fix: gate recorded markdown at its renderer and close remaining render-budget gaps * fix: replace per-key render caps with one structural budget per recorded value * fix: bound component fan-out and text alongside the structural budget * fix: make component fan-out cumulative and cap the parsed data-test checklist * fix: bound the whole recording, graph contents, metadata strings and timer bursts * fix: keep the published loader path, charge object keys, refuse huge serialized fan-out * fix: cap flat maps a renderer turns into rows (args, schema properties) * fix: refuse structure hidden past the depth ceiling and bound errored samples * fix: count array-shaped argument collections against the row cap * feat: paint canvas pixels into the snapshot * fix: budget canvas encoding per snapshot and bound the unknown-kind error * fix: cap flow graph overlay fan-out and condense budget comments * docs: teach the raw-app prompt about data-wm-no-record |
||
|
|
2bf7746cdd |
fix: operators cannot archive or delete flows and apps (#10322)
`create_flow`/`update_flow` and `create_app`/`update_app` reject operators, but `archive_flow_by_path`, `delete_flow_by_path` and `delete_app` did not — so an operator with folder write could delete a flow or app they were not allowed to edit. Scripts already get this right (archive is guarded, delete is admin-only). Verified on a live instance: all three returned 2xx for an operator before, 401 after, and a non-operator member with the same folder write is unaffected. |
||
|
|
80ad357c06 |
fix: scope cd in parser wasm dev.nu so cli install path resolves (#10329)
* fix: scope cd in parser wasm dev.nu so cli install path resolves Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016xKBCiRBL2NkvpgontuwYf * Update dev.nu --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4d3ff0299f |
feat: mark failed jobs as resolved so handled failures stop showing red (#10319)
* feat: mark failed jobs as resolved so handled failures stop showing red Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: constrain auto-resolve to the proven retry chain and honor resolved filter everywhere Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: apply resolved filter to queue-union, concurrency and delete paths, bound note Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: sweep resolutions on workspace delete, verify helper args, enforce UI limits Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: count resolution note in characters on both sides of the API Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: skip the queue lookup for cancel-all under the resolved-only filter Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: converge retry auto-resolution from either commit order, keep notes on re-resolve Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: correct the idempotency claim on the retry auto-resolve sweep Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: gate resolution notes and attribution behind enterprise, add note popover Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: hide resolution from operators, exclude flow steps, enforce EE licence at runtime Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: add job_resolution.automatic to the summarized schema Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: preserve stored attribution when re-resolving without a valid licence Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: condense the attribution-preservation comment to four lines Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: validate resolution notes by code point instead of a UTF-16 maxlength Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep the resolution popover open when a note is rejected Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: offer to resolve the original failure after a successful re-run Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: verify supersession server-side and stop re-runs overwriting notes Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: apply tag scope to the superseding run Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: exclude obscured cross-workspace runs from resolution actions Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a8455acd7d |
feat: make bigquery and snowflake script languages available in CE (#10324)
* feat: make bigquery and snowflake script languages available in CE * docs: add snowflake to backend cargo feature map * fix: stop logging the snowflake bearer token at debug level |
||
|
|
9cef724ff2 |
feat: bind WAC approval urls to a named wait_for_approval step (#10317)
* feat: bind WAC approval urls to a named wait_for_approval step Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: reject duplicate WAC approval step keys instead of renaming them Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: reject WAC approval links minted for a step that is not awaiting approval Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: bind WAC approval links to the awaiting step and stop step key aliasing Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: reject empty approval keys and scope minted-key writes to the workspace Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: enforce WAC approval binding at consumption and reject colliding keys Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: make WAC approval binding and collision checks atomic, harden TS step keys Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: decrement WAC suspend atomically instead of from a pre-lock snapshot Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore: add sqlx cache entry for the atomic WAC suspend decrement Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: omit empty approver param from python get_approval_urls Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test: pin the suspend-snapshot decrement and the colliding-mint race Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test: drop the suspend-snapshot interleave test, it cannot both be stable and discriminate Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: reject step keys that cannot be minted as a URL path segment Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
15a6382c89 |
remove unused mut breaking backend CI (#10320)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
65db58bfda |
fix(frontend): pin sveltekit version.name so builds are reproducible across architectures (#10315)
* fix(docker): pin frontend build stage to linux/amd64 Rollup selects platform-specific native binaries that can emit different content-hashed chunk filenames for identical sources. The frontend assets are embedded into the Rust binary via rust_embed, so building the stage once per target architecture produced amd64 and arm64 images whose HTML references `_app/immutable/chunks/<hash>.js` files that only exist in that architecture's image. In a mixed-architecture cluster, a page served by a pod of one arch 404s on JS/CSS fetched from a pod of the other. Pinning the stage makes both image variants embed byte-identical assets. The stage output is JS/CSS/HTML/WASM only, so the build platform does not leak into the artifacts. Fixes WIN-2242 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: tighten frontend platform-pin comment Vite 8 bundles with rolldown, not rollup; name the right bindings and keep the constraint to four lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(frontend): make the build reproducible so mixed-arch clusters agree on asset names SvelteKit defaults `kit.version.name` to `Date.now().toString()`, so every build of the same commit gets a different version string. It is embedded in the client chunk (and in the `__sveltekit_<hash>` global derived from it), which changes that chunk's content hash and cascades into new filenames for roughly a quarter of `_app/immutable`. The assets are baked into the binary via rust_embed, so the amd64 and arm64 images of one release ship different `chunks/<hash>.js` names: in a mixed-architecture cluster, HTML served by a pod of one architecture 404s on assets requested from a pod of the other. Measured on the published windmill:1.770.0 images: 224 of 863 asset filenames differ between the two architecture variants, yet 854 of 855 chunks are byte-identical once chunk-name references are normalized. The single genuinely differing chunk is the one carrying the timestamp. The bundler is deterministic across architectures; the timestamp is the whole divergence. Pinning the version to the package version (overridable via WM_BUILD_VERSION) makes repeat builds byte-identical. `version.pollInterval` is 0 and nothing reads the `updated` store, so this has no runtime behavior change. This supersedes pinning the Docker frontend stage to linux/amd64, which fixed the symptom by building the stage under emulation on the arm64 builder — that cost 32 minutes of QEMU time per build and left the underlying non-determinism in place. Fixes WIN-2242 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(frontend): key the sveltekit version on the commit sha The package version only moves on releases, but `:dev` and RHEL images are published on every main push. Two such deployments would then advertise the same SvelteKit version, and SvelteKit only recovers from a chunk that 404s after a redeploy (client.js: "Referenced node could have been removed due to redeploy") when the deployed version differs from the baked-in one, so an open tab would render an error page instead of reloading. Pass the commit sha through WM_BUILD_VERSION from every workflow that builds the root Dockerfile, so the value is identical across the per-architecture builds of one commit and distinct between commits. The package version stays the fallback, which keeps unwired builds architecture-consistent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(docker): declare WM_BUILD_VERSION in the RHEL frontend stages The RHEL workflows copy docker/RHEL{8,9}/Dockerfile over the root one before building, so the build-arg was unconsumed there and those images fell back to the package version: two RHEL builds between releases would share a SvelteKit version across different manifests. Also switch the root declaration to the `ARG name=""` form used by `features`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: keep the version-arg rationale in one place The root Dockerfile comment restated what frontend/svelte.config.js already documents; point at it instead, matching the RHEL Dockerfiles. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
71b7135cf2 |
feat: multiple homepage sort orders via an efficient merged runnables endpoint (#10297)
Adds recently-updated / oldest / name A-Z / name Z-A sort orders to the homepage (WIN-2236), produced server-side by a new merged, index-backed, keyset-paginated GET /w/{workspace}/runnables/list so a chosen order is globally correct across scripts + flows + apps and stays efficient on large workspaces.
- Backend: UNION ALL of script/flow/app ordered by index (Merge Append + LIMIT); keyset (sort_key, path, kind, tiebreak) cursor; per-branch LIMIT bounds correlated projections; starred-first pinning; RLS + scope-token filters in SQL. Archived view returns the latest row per path. Migration adds time + lowered-name indexes (built CONCURRENTLY).
- Frontend: server-side sort/kind/owner filters + hybrid search (instant client + on-demand server pagination); file-explorer tree with every folder and your user namespace as lazy-loaded top-level nodes (per-owner "Load more", nested subfolders, bounded "expand all", in-place re-sort without collapse or flicker); the client sorts by the server fetch ordinal to reproduce the endpoint's exact order; empty state distinguishes an empty workspace from too-narrow filters.
Reviewed clean by Claude and Pi (good to merge) and Codex (mergeable).
|
||
|
|
1973bc806b | migrate to opus 5 | ||
|
|
113f41bab5 |
chore(main): release 1.770.0 (#10309)
* chore(main): release 1.770.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.770.0 |
||
|
|
03e727777c |
chore: auto-allow rm in /tmp and git repos, plus read-only gmail (#10307)
* chore: allow /tmp rm and read-only gmail in local permission rules * fix: gate rm outside /tmp via PreToolUse hook and gate gmail drafts * fix: reject shell expansion and multi-line commands in rm guard * fix: make rm guard allow-only with Bash(rm:*) ask as safety net * fix: reject quotes and backslashes in rm guard to block obscured traversal * fix: switch rm guard to deny-by-default whitelist of safe /tmp operands * fix: treat lone dash as rm operand, not an option flag * fix: defer option tokens containing glob chars in rm guard * feat: also auto-allow rm strictly inside git working trees under $HOME * feat: auto-allow deleting linked worktree root folders, still guard primary checkouts * fix: restrict globs to /tmp and validate post-operand option tokens in rm guard * docs: correct rm guard rationale to not overclaim git recoverability |
||
|
|
2143d45815 |
fix: WAC wait_for_approval reads its own approval result, not the first (#10314)
In prepare_checkpoint_for_resume the resume_job lookup took the oldest row
for the job (ORDER BY created_at ASC LIMIT 1), so a WAC workflow with
multiple sequential wait_for_approval() calls always read the first
approval's result for every step. Consumed rows are never deleted, so the
2nd and 3rd approvals inherited the 1st's result (all showed approved:true
even if the 2nd was cancelled and the 3rd timed out).
Track the resume_job row ids consumed by earlier approval steps in the
checkpoint (consumed_resume_ids) and exclude them, so each step reads its
own row. This is channel-agnostic and needs no clock reasoning:
resume_job.resume_id is only hash(step_key) for the inline resume URL; the
approval page, the in-run approve button, Slack, Teams and resume-as-owner
all store a random resume_id, so filtering by resume_id would drop those
approvals and return approved:false even for a legitimate approval. A
timed-out step matches no row and still falls to the else branch returning
{approved: false}.
Adds a regression test driving three sequential approvals (approved,
cancelled, timed-out) against Postgres.
Fixes WIN-2241
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
28a79ced15 |
feat: add explore button for object storage resources (#10306)
* feat: add explore button for object storage resources in resource list Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: make s3 drawer tooltip reflect explored resource Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: honor workspace prop in global s3 explorer and add resource connection error state Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: use picker's effective workspace in S3FilePreview requests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: pass acting workspace to explore button in ResourcePicker Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * chore: update ee-repo-ref to f78df23339e3136e8b6e9148a509508633448dd2 This commit updates the EE repository reference after PR #686 was merged in windmill-ee-private. Previous ee-repo-ref: efb5e014fec34fc580b9dbb1b260494dd76c5462 New ee-repo-ref: f78df23339e3136e8b6e9148a509508633448dd2 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> |
||
|
|
85008e47b4 |
fix: pass Windows system env vars to R renv install subprocess (#10313)
Claude-Session: https://claude.ai/code/session_01WTZ5UBBLNh2rkgfNzUmCWs Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
48618cff8c |
feat: Add image when publishing a project (#10310)
* refactor(hub): remove per-item Publish to Hub entry points Publishing to the Hub now happens exclusively through the folder-level deploy-to-hub flow (/folders). Remove the standalone entry points: - script detail page menu item (and the SCRIPT_VIEW_SHOW_PUBLISH_TO_HUB const that gated it) - script list row dropdown item - raw app editor menu item, its zip-download drawer and publishToHub() - long-dead commented block in AppEditorHeader Also drop the now-orphaned URL helpers (scriptToHubUrl, flowToHubUrl, appToHubUrl, rawAppToHubUrl) from lib/hub.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(hub): upload a custom project logo from the deploy-to-hub drawer Add a Logo field to the bundle metadata form: a drag-and-drop dropzone (png/svg, 512KB client-side cap mirrored server-side by the Hub) that turns into a live replica of the Hub project card once an image is picked, so the logo can be judged in context before publishing. The logo is pushed after the draft's items/migrations via the new POST /projects/{slug}/logo proxy in hub_publish.rs (slug validated by construction, `logo: null` forwarded to clear). Leaving the field empty never touches the Hub's existing logo, so re-publishing a bundle keeps it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hub): logo removal, safer mime inference, explicit clear semantics Review follow-ups on the project logo upload: - Removing a published logo is now possible: hubLogo is three-state (undefined = leave the Hub's logo alone, null = clear on publish, object = upload). Rehydration reads has_logo so the drawer shows a "Remove on publish" affordance when the Hub already has one, with an undo banner before publishing. - hub_publish.rs uses a double-Option for the logo field: a missing `logo` key is now a 400 instead of being serialized as `logo: null`, which the Hub interprets as an explicit clear — POSTing `{}` can no longer silently delete a project's logo. - Client mime inference prefers the browser-reported file.type over the filename extension, so a PNG misnamed *.svg no longer produces a broken preview and a guaranteed server-side sniff rejection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Update frontend/src/lib/components/workspaceSettings/deployToHubSession.svelte.ts Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * Update frontend/src/lib/components/workspaceSettings/DeployToHub.svelte Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix(hub): validate logo size/mime/base64 in the proxy, document the endpoint - Enforce the logo constraints in windmill-api itself instead of relying on the browser and remote Hub: a route-level DefaultBodyLimit sized for a max logo in base64 (+JSON envelope) overrides the global request limit, and the handler validates the mime allowlist, base64 alphabet and decoded length (512KB cap) before anything is forwarded. - Add /w/{workspace}/hub/projects/{slug}/logo to openapi.yaml (with the ProjectLogoBody schema) and regenerate the frontend client. - Drop a narrating comment on the hidden file input. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
f00fcb2d1b |
fix: show scheduled singlestepflow runs in flow history sidebar (#10312)
* fix: show scheduled singlestepflow runs in flow input history Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: only match flow-wrapped singlestepflow rows in flow history singlestepflow wraps either a script or a flow; a script and flow may share a runnable_path, so filter flow history to flow-wrapped rows via the wrapped module type. Extends the regression test to cover the same-path collision. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: surface scheduled singlestepflow runs in script history too Scheduled scripts with a dynamic-skip handler or native retry also run as singlestepflow. Include that kind for ScriptPath history, filtered to script-wrapped rows so a same-path flow run does not leak in. ScriptHash is untouched (these wrappers carry no runnable_id). Test covers both directions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
992ed01244 |
fix: do not apply workspace display name on git-sync pull (#10308)
* fix: do not apply workspace display name on git-sync pull The workspace display name is stored in settings.yaml and was re-applied on every pull via changeWorkspaceName. Because settings.yaml is shared across the branches of a repo, a workspace could have its name overwritten by another workspace that syncs the same repo. Keep name in settings.yaml for reference (written on push) but stop applying it on pull. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: consolidate workspace-name rationale to one comment (review nit) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: bump git-sync hub scripts to windmill-cli 1.769.1 Repin GIT_SYNC_PULL_SCRIPT_PATH (28795->28808), LATEST_GIT_SYNC_SCRIPT_PATH (28796->28809) and frontend gitInitRepo to the hub scripts bundling windmill-cli@1.769.1, so backend automatic git pulls no longer apply the workspace display name (the CLI fix in this PR only reaches auto-pull via the pinned hub script bundle). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a26ea4d43f |
chore(main): release 1.769.0 (#10302)
* chore(main): release 1.769.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.769.0 |
||
|
|
3cf7a390a3 |
fix: pin validated DNS address to close SSRF DNS-rebinding TOCTOU (#10303)
* [ee] fix: pin validated DNS address to close SSRF DNS-rebinding TOCTOU validate_url_for_ssrf resolved the host, checked every address was public, then discarded them. Callers re-used the hostname and let stock reqwest re-resolve at connect time, so a TTL-0 DNS rebinder that answered a public IP at check-time and an internal one (e.g. 169.254.169.254) at connect-time slipped straight through the guard. Return the resolved addresses as a ValidatedTarget and pin them onto the client that connects, so validate-time and connect-time target the same address. Covers the AI proxy and worker AI-agent base_url (the primary readable-SSRF sink), AI OAuth token_url, MCP server + OAuth registration/discovery/token endpoints, SAML metadata, and the WebSocket trigger connect. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 22abd6d4e229f1206a13ebee8a6a9b808cd82a0d This commit updates the EE repository reference after PR #684 was merged in windmill-ee-private. Previous ee-repo-ref: 700feb02ef1b96758ba9425358dbebc83bc02c61 New ee-repo-ref: 22abd6d4e229f1206a13ebee8a6a9b808cd82a0d 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> |
||
|
|
1478d12eb3 |
perf: optimize get_datatable_full_schema to avoid timeout on large catalogs (#10304)
pg_get_full_schema built each column row with three per-column correlated subqueries (default value, primary-key EXISTS on pg_index, pk constraint name on pg_constraint). On large catalogs those run once per column and the introspection times out. Replace them with plain joins to pg_attrdef and the table's single primary-key constraint, so the planner does one hash/merge join instead of O(columns) index searches. Output is byte-for-byte identical. Fixes WIN-2239 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
75acf7207b |
fix: pin table actions column so it stays visible on narrow screens (#10301)
* fix: pin table actions column so it stays visible on narrow screens Wide DataTables (folders, variables, resources) scroll horizontally on small screens, pushing the trailing per-row actions column (the ⋯ menu, Edit/Delete, and folders' "Publish to Hub") off the right edge where it was effectively unreachable. Add an opt-in `stickyEnd` prop to Cell that pins a column to the right of the scroll container with an opaque background and a left divider, and apply it to the actions column (header + body) on the folders, variables, and resources pages. The background is opaque (bg-surface / bg-surface-secondary) rather than the row's translucent hover tint, so cells sliding under the pinned column are occluded instead of bleeding through. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: keep resources actions cell as table-cell so sticky pins correctly The workspace resources actions cell used class="flex justify-end" on the Cell, which forces the <td> to display:flex. A flex box inside a table row is wrapped in an anonymous table-cell, so position:sticky on it is constrained to that wrapper and no longer pins to the scrollport — the header stayed pinned while the row actions scrolled away. Move the flex layout to an inner <div> so the <td> keeps display:table-cell and the stickyEnd pin works. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: address review nits on pinned actions column - resources Workspace table: add `last` to the body actions cell so its right padding (sm:pr-6) matches the header and the other tables. - variables table: isolate the refresh-error ping indicator's stacking context so its z-50 can't paint over a sticky-pinned actions column scrolling past it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
010059a449 |
feat(hub): surface data pipelines in deploy-to-hub drawer (#10299)
* feat(hub): surface data pipelines in deploy-to-hub drawer The predeploy step listed a folder's scripts with no indication that some form a data pipeline. Add a "Data pipeline" summary row (step count + "View pipeline graph" drawer rendering the asset-graph cascade) and tag pipeline-member scripts with a Pipeline badge in the item list. Fixes WIN-2238 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hub): drop misleading node-inspect hint from pipeline graph drawer The read-only graph doesn't wire node selection, so the "Click a node to inspect it" copy promised interaction that doesn't happen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(hub): render pipeline graph inline above the list, collapsed by default Replace the "View pipeline graph" drawer with an inline collapsible panel above the deploy item list for pipeline folders. Collapsed by default so the selection list stays the first thing in view; expanding reveals the folder's asset-graph cascade in place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hub): don't let the inline pipeline graph capture the drawer scroll Add an opt-in scrollZoom prop to AssetGraphCanvas (default true, preserving the full-height editor/player). The inline deploy-to-hub panel sets it false so wheel gestures over the 420px graph scroll the surrounding drawer instead of zooming the canvas and swallowing the scroll. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1d25d7539e |
feat(pipeline): collapse secondary top-bar controls into an overflow menu (#10300)
* feat(pipeline): collapse secondary top-bar controls into an overflow menu The data-pipeline editor top bar crowded primary actions (mode toggle, Run pipeline, Save) with secondary ones (Record, Download recording, Macros), which overflowed on small screens. Move the recorder and Macros into a single overflow (⋮) menu, and surface recording only while armed as a compact inline "Recording" disarm pill rather than an always-present Record button. Fixes WIN-2237 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(pipeline): hoist armed-recorder hint to a shared const The overflow-menu Record item and the inline armed pill both showed the same "Recording armed…" tooltip as separate literals, which could drift. Share one RECORDING_ARMED_HINT const. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(pipeline): keep the overflow-menu rationale at a single site Address Codex P2: the same crowding/overflow rationale was narrated at three sites. State it once on the overflowMenuItems derived; the pill and DropdownV2 mount keep only their local, non-duplicated notes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c24d6f9d11 |
chore(main): release 1.768.0 (#10281)
* chore(main): release 1.768.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.768.0 |
||
|
|
30d8104edc |
feat: alert on expired online license key (#10295)
* [ee] feat: alert on expired online license key Wire alert_on_online_license_expired into the periodic monitor loop (verify_license_key_f), server-mode gated so only servers report to the alerts table and critical channels. Add the ee_oss stub so the enterprise-without-private build still compiles. Closes the gap where an expired online (renewable) license force-set externally (env var / CI / k8s) halted all jobs with only a stdout tracing::error! and no critical alert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: point ee-repo-ref at license-expired-alert EE branch Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 9e63619688588fda434dfa06ed585f050e75ee67 This commit updates the EE repository reference after PR #682 was merged in windmill-ee-private. Previous ee-repo-ref: 7847711567a9c66da6a5c85d176b8cacc5aa7a7f New ee-repo-ref: 9e63619688588fda434dfa06ed585f050e75ee67 Automated by sync-ee-ref workflow. * chore: bump ee-repo-ref to license-expiry alert review fixes Point at the EE follow-up (windmill-ee-private#683): cross-replica dedup via acquire_lock and no false recovery on malformed key replacement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to eb8733a36010a7509b438903e95edfa293da079b This commit updates the EE repository reference after PR #683 was merged in windmill-ee-private. Previous ee-repo-ref: 562a306d9b66624b28ff90958f8b45d8db5481b9 New ee-repo-ref: eb8733a36010a7509b438903e95edfa293da079b 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> |
||
|
|
9713e6074d |
fix: resolve svelte/style export conditions in raw-app CLI bundler (#10294)
The `wmill app dev`/`app bundle` esbuild config never set custom export conditions, so it only used esbuild's browser-platform defaults (browser/module/import/default). Packages that gate their entry points behind other conditions failed to resolve: - tailwindcss v4 exposes its CSS entry only under `style` (`@import "tailwindcss"` -> ./index.css) - flowbite-svelte exposes its entry only under `svelte` (-> raw .svelte) Enable the needed conditions, split by scope: - `style` + `module` are global (DEFAULT_BUILD_OPTIONS): `style` benefits any app (Tailwind, CSS libs), and `module` must be re-added because esbuild drops its auto-included `module` default once any custom condition is set. - `svelte` is gated per-app via conditionsFor(frameworks.svelte). It points at raw .svelte sources that only compile with the Svelte plugin (itself loaded only for Svelte apps), so enabling it globally would make a Svelte-dual-published import in a plain app hard-fail with no .svelte loader. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
53ad86cd1e |
docs: fix stale detach_dev_workspace comment on parent_workspace_id (#10296)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
161c7f4655 |
test(cli): drain async dependency jobs after sync push to fix flake (#10293)
* test(cli): drain async dependency jobs after sync push to fix flake Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(cli): condense waitForDeploymentJobs comment Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
717e38a0c6 |
feat: let a workspace fall back to the instance critical alert channels (#10292)
* feat(alerts): let a workspace fall back to the instance critical alert channels A workspace with no error handler had no way to surface failed jobs, and the instance critical alert channels a superadmin already configured (Slack, Teams, email) were unreachable from a workspace: the workspace Slack error handler posts with the workspace's own bot token, not the instance one. Adds an opt-in workspace setting that reports failed jobs to those channels when, and only when, no workspace error handler is configured. The report is send-only: it skips the `alerts` table so workspace job failures never flood the instance-wide feed superadmins triage. Rejected on cloud (the channels belong to the instance operator, who is not the tenant) and on fork workspaces (throwaway copies of a parent's runnables). Settable from workspace settings and from the new-workspace screen. The opt-in and the existing `mute_critical_alerts` flag are folded into the query already behind WORKSPACE_ERROR_HANDLER_CACHE, so a failed job costs no extra round trip, and workspaces with neither a handler nor the opt-in return before the per-runnable mute lookup. * chore(sqlx): add offline query cache entries for the new settings queries * refactor(alerts): make instance alerts a destination tab and address review Instance alerts are a fifth error-handler destination rather than a separate toggle: the backend already treats them as mutually exclusive with a handler script, so one "where do failures go?" control matches the semantics and drops the inert-while-a-handler-is-set state. The tab is offered on the workspace error handler only, not on schedules or triggers. Review fixes: - the fork boundary is enforced at dispatch (join on parent_workspace_id), so a workspace attached as a fork/dev after opting in stops reporting; attaching also clears the stored flag, and the settings page never selects a tab it does not render, which would have submitted a value the API rejects on a fork - mute_critical_alerts no longer gates this path: it is the UI-feed mute, and this path writes no feed entry - cancellations are not reported: they are a human action, and this destination has no per-workspace mute of its own - per-workspace throttle with a rollup count, so a flapping runnable cannot turn into unbounded Slack/SMTP traffic on channels shared by the whole instance - log the dispatch, audit the flag, name the columns in the rename INSERT, drop the generated migration placeholders * chore(alerts): state the fork/cloud invariant on canUseInstanceAlerts * chore(sqlx): cache the attach_dev_workspace settings update |
||
|
|
9b182aaf38 |
fix: surface workspace ids on duplicate names and explain fork promotion (#10291)
* fix: disambiguate same-named workspaces in the workspace menu Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: explain why git promotion is absent on a fork Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: link a fork to dev-workspace pairing from git sync settings Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
bf16e7d49a |
feat: surface workspace-script advanced settings in flow editor (#10289)
* feat(flow-editor): surface workspace-script advanced settings in flows
Workspace-script steps in a flow could not view or edit script-level
runtime settings (concurrency, cache, timeout, debounce, dedicated
worker, priority, delete-after-use). The concurrency and cache tabs
only showed a "set it on the script" warning with no value and no way
to act on it.
- Add ScriptAdvancedSettings, a reusable subset of the script editor's
runtime settings, and two entry points that reuse it:
- WorkspaceScriptSettingsDrawer: a mini settings drawer reachable from
the flow step (header "Settings" button and the delegating tabs),
saving a new script version with the code left unchanged.
- an inner "Settings" drawer inside ScriptEditorDrawer, saved together
with the code.
- Replace the concurrency/cache delegation warnings with a box that
fetches the referenced script's current value and offers an
"Edit script settings" shortcut (useWorkspaceScriptSettings loader).
- Add ScriptSettingsBadges showing active advanced settings, in the
standalone script editor top bar, the edit-code drawer, and above the
workspace-script step preview.
Fixes WIN-2233
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): keep subflow concurrency note distinct from workspace-script
The concurrency delegation box is workspace-script specific; subflow
steps now keep a plain limitation note instead of the script settings
shortcut.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): preserve all script fields when saving settings-only version
Building the createScript body by hand dropped codebase/labels/envs and
other fields on the new version. Spread the loaded script instead and
override only lineage, matching ScriptEditorDrawer's save.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): address review — settings-save safety and stale display
- WorkspaceScriptSettingsDrawer: keep settings-only saves from hijacking
execution identity or discarding the author's draft (preserve_on_behalf_of
+ skip_draft_deletion), and normalize cleared concurrency/debounce keys to
undefined so blanks don't become shared global keys.
- ScriptEditorDrawer: normalize cleared keys in its save too (the inner
settings drawer edits them).
- FlowModuleComponent: reload the surfaced concurrency/cache values + badges
after a header settings/code save; gate settings editing on customUi.scriptEdit.
- useWorkspaceScriptSettings: sequence-guard load() against stale overwrites.
- Add unit tests for getActiveScriptSettingsBadges.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): round-3 review — concurrency-safe save, load guards, UI gates
- WorkspaceScriptSettingsDrawer: drop auto_parent so a settings-only save uses
the loaded parent as an optimistic-concurrency guard (fails loudly instead of
silently reverting a concurrent deploy); sequence-guard openDrawer so a slow
load for a previous script can't clobber a reopened one.
- useWorkspaceScriptSettings: clear loading in the superseded/early-return path
so a hub/empty step can't spin forever.
- ScriptBuilder: gate the clickable settings badges on customUi.topBar.settings
and settingsPanel.disableRuntime.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): round-4 review — template, load-error, legacy-zero handling
- WorkspaceScriptSettingsDrawer: stop forcing is_template=false so saving a
setting on a template keeps its template status; show a recoverable error
(with Retry) when the settings load fails instead of spinning forever.
- scriptSettings/FlowModuleComponent: treat non-positive concurrent_limit and
timeout as unset (legacy zero rows), so no "Max 0 executions"/"Timeout 0s".
- Add badge tests for the non-positive cases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): round-5 nits — neutral card wording, load-error surfacing, cache zero
- WorkspaceScriptSettingInfo: neutral "managed on the referenced workspace
script" header (no longer claims "configured" when unset) and a distinct
error line so a failed load isn't misread as "not set".
- useWorkspaceScriptSettings: expose an error state; thread it into the
concurrency and cache cards.
- Treat cache_ttl <= 0 as unset, matching concurrency/timeout; add test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(flow-editor): icon-only script action buttons + gate settings in local-dev
- Gate the workspace-script settings actions (header button, clickable badges,
Concurrency/Cache shortcuts) on the settings drawer actually being mounted, so
the local-dev flow editors (Dev.svelte / flows/dev) that provide the context
store but never render the drawer keep the values read-only instead of showing
no-op controls.
- Make the script action buttons icon-only with clear hover popovers to save
space in the crowded step/script-editor top bars: Edit, Settings and Fork in
the step header, Settings in the edit-code drawer, and the settings badges
(icon chip + label/value popover).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): round-6 nits — a11y names + accurate read-only reason
- Add aria-label to the icon-only Edit/Settings/Fork buttons and the setting
badges so keyboard/screen-reader users get an accessible name (the hover
popover alone didn't expose it).
- WorkspaceScriptSettingInfo takes a noEditReason so the read-only explanation
matches the actual gate (hub / hash-pinned / unavailable-in-this-editor)
instead of always blaming hub/pinned — fixes the wrong reason shown in the
local-dev flow editors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(flow-editor): drop narrating comment on the no-edit-reason derived
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flow-editor): bind settings save completion to the drawer target
The drawer is a singleton, so a save that outlived a reopen ran the new
target's callback and closed its drawer, discarding edits in progress.
Capture the target sequence and callback at save time: the captured
callback still fires (it refreshes the script it belongs to) while the
close, error toast and saving flag only apply if the target is unchanged.
Reopening also resets the saving flag, which the seq-guarded save no
longer clears for a superseded target.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
a29e13fd18 |
reference the file-search worker by its packaged .js name (#10290)
svelte-package does not rewrite the string literal inside new URL(), and ships only the compiled searchWorker.js — so the .ts URL is dangling for any downstream consumer of @windmill-labs/components (rollup: Could not resolve searchWorker.ts). Vite maps .js back to the .ts source in-repo, so both builds resolve. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f02df7fc45 |
feat(monitor): make between-steps zombie flows hand-recoverable (#10287)
* feat(monitor): make between-steps zombie flows hand-recoverable When a worker is OOM-killed mid state-transition, the flow is reaped as a between-steps zombie (children all success, module still InProgress). We do not auto-recover (a re-driven transition can OOM again), so instead: - Append actionable recovery guidance to the cancellation reason when the reaped step's state is derivable (every child a success completion): which step, iterations completed, raise memory then restart-from-step (UI + API). - Restart-from-step now reuses a zombie step verbatim (InProgress with all children successful) and restarts from the next step, so no completed child re-runs; downstream steps re-derive its result from flow_jobs on demand. - Cast flow_status ::text in the reaper query: reading the jsonb column as Box<str> included the binary version byte and silently failed FlowStatus parsing (disabling the restart-not-yet-started branch since the v2 migration). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): only reuse a between-steps zombie step that provably finished Address review findings on the zombie-restart reuse path: - Require structural completeness (FlowStatusModule::is_between_steps_complete): a serial for-loop / branch-all reaped mid-fan-out has an all-success prefix but unrun remaining iterations, so the cursor must sit on the last element; while-loops are never derivable (continuation is a post-iteration condition). Parallel containers preallocate all children, so success alone is conclusive. Shared by the monitor guidance and the restart resolution. - Decline reuse when the step carries stop_after_if / stop_after_all_iters_if: those predicates decide whether downstream steps run, and reuse would bypass them; such a step re-runs instead. - Decline reuse when the zombie step is the last module (advancing past it lands on the failure step); it falls back to the existing re-run path. - Unit tests for is_between_steps_complete and an integration test asserting a mid-iteration serial-loop zombie is re-run, not reused. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): align zombie recovery guidance with restart eligibility Address CI review findings: - Exclude skip_if / suspend / sleep (not just stop predicates) from reuse via FlowModule::allows_zombie_reuse, so a skipped/suspend-armed step is never synthesized as Success (which would strand a restart waiting on an approval it never armed). - The reaper does not load the flow definition, so it cannot know whether restart will reuse or re-run a given step; reword the guidance to state both outcomes (reuse where derivable, re-run for the flow's last step or one carrying a stop/skip condition, approval, or sleep) instead of promising "no re-run". - Make the mid-iteration regression test exercise the cursor-completeness guard: a downstream step makes the loop non-final, so reuse is prevented only by the guard; a truncated loop result would then fail the assertion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): never let zombie reuse swallow a nested restart request A nested restart (RestartedFrom.nested) descends into the restart step's child to re-run an inner step. For an eligible zombie BranchOne/Subflow the outer branch_or_iteration_n is None, so reuse fired, skipped the container, and the explicitly requested inner step never re-ran. Thread the presence of a nested chain into restarted_flows_resolution and decline reuse when set. Regression test added (RED without the guard: the nested target is reused instead of re-run). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): don't auto-requeue preprocessor zombies as unstarted flows The ::text parse fix re-activated the "hasn't started yet, restart it" branch, but its `modules[0] == WaitingForPriorSteps` check also matches a flow whose preprocessor is still InProgress (step == -1, first module waiting). Requeuing such a flow re-runs the preprocessor, duplicating side effects / repeating the OOM. Gate the branch on FlowStatus::is_not_yet_started, which also requires the preprocessor (if any) to be WaitingForPriorSteps. Unit-tested. Also drop the numbered procedural narration from the happy-path test comments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): only emit restart guidance for restartable (deployed, top-level) flows The recovery guidance points operators at the run page's "Re-start from" button and the restart API, but both require a top-level deployed flow: a preview has no flow path (the button is hidden, the API 400s) and a subflow child restarts via its root, not itself. Gate the guidance on runnable_path IS NOT NULL AND parent_job IS NULL so previews/subflows keep the existing wording instead of being told to use a button/endpoint that isn't there. Verified end-to-end: a reaped preview gets no RECOVERY block, a reaped deployed flow does. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): gate recovery guidance on kind='flow' to match the restart surface Addresses review nit: a pathful editor preview (kind='flowpreview' with a runnable_path) satisfied the previous runnable_path check but the run page only renders the "Re-start from" button for kind='flow'. Match that condition exactly so previews/singlestepflow keep the plain wording. Verified end-to-end: a reaped pathful preview now gets no RECOVERY block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): disable zombie reuse for raw-flow (editor preview) restarts A JobPayload::RawFlow restart queues the request's current, possibly EDITED, definition, but restarted_flows_resolution validates reuse against the completed job's STORED definition. For an eligible preview zombie, editing the restart step and restarting from it would synthesize Success from the old children and skip the edit. Thread allow_zombie_reuse into the resolver (true only for JobPayload::RestartedFlow, which queues the stored definition) and decline reuse for raw-flow restarts. Regression test added (RED without the guard: the edited step is skipped and the old result is reused). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(sqlx): add offline cache for zombie_flow_recovery test queries The integration test's UPDATE v2_job_completed queries had no .sqlx entry, so the CI SQLX_OFFLINE build of the test failed to compile. Regenerated with --all-targets --features deno_core,quickjs to capture the test-target queries. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(monitor): drop procedural narration from the raw-flow zombie test Per AGENTS.md (comments record constraints, not narration): remove the two step-describing comments the reviewer flagged; the test doc comment already carries the durable rationale. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): restrict zombie reuse to monitor-reaped flows The reuse predicate matched the InProgress/all-children-success shape without checking provenance, so an ordinary force-cancel at the same boundary (a child succeeded before its parent transition landed) would also be reused, dropping the usual restart-from-step re-run. Gate reuse on canceled_by = 'monitor' (the username the zombie reaper cancels with). Regression test added (RED without the guard: a user-cancelled flow reuses the child instead of re-running it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(monitor): reuse zombie step on Some(0) too, so the run-page button works The run page's "Re-start from" button always sends branch_or_iteration_n = 0 (never omits it), but reuse only fired for None, so the exact UI path the recovery message points to would re-run the children instead of reusing them. Treat a whole-step restart (None or Some(0)) as reuse-eligible; Some(n>=1) keeps the explicit partial-container restart. Verified against the live EE restart API with branch_or_iteration_n=0: all loop-iteration child UUIDs are reused. Happy- path test now sends Some(0) to match the button. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
8eb36ce008 |
fix: treat concurrent_limit/timeout <= 0 as unset instead of a zero cap (#10288)
* fix: treat concurrent_limit/timeout <= 0 as unset instead of a zero cap Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: flow-step timeout <= 0 inherits the script timeout, not the global default Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
68daed8501 |
refactor: custom-instance datatable connection handling (#10271)
Attach custom-instance datatables in the DuckDB executor through a DuckDB secret instead of an inline connection string, and route postgres triggers on custom-instance datatables through a dedicated custom_instance_replication_user role (with its own auto-generated password in global_settings). Normalize custom_instance_user attributes on server boot. Claude-Session: https://claude.ai/code/session_01Tp6NNNinCB8dwWqGaFXDRF Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
65e504146d |
feat: data-pipeline recorder, interactive player, and deploy-to-hub recording (WIN-2156) (#10055)
* feat(frontend): add data-pipeline run recorder and interactive player Adds a recorder/player for data pipelines, mirroring the existing flow and script recorders. Arm "Record" on a pipeline, run it, and the resulting cascade is captured into a downloadable JSON that the /replay player can rerun fully offline. Because a pipeline run is a cascade of independent jobs (not a single root SSE job like flows), the recording captures three things: the resolved asset graph, the per-node cascade status timeline (from the orchestrator's onUpdate), and each node's job stream (opened via getupdate_sse on launch). The player renders the graph read-only, animates the recorded node transitions in real time, and lets you click any node to inspect its recorded args, logs and result — reusing the same JobLoader replay path the flow/script players use (setActiveReplay + isReplay gating), so no network calls are made during replay. - recording/types.ts: PipelineRecording, PipelineTimelineFrame, RecordedNodeState - recording/pipelineRecording.svelte.ts: createPipelineRecording() store - recording/PipelineRecordingReplay.svelte: the player component - replay/+page.svelte: dispatch type === 'pipeline' - pipeline/[folder]/+page.svelte: Record toggle + Download recording; capture the whole-pipeline / bounded cascade run Fixes WIN-2156 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(frontend): capture DuckLake/datatable data samples in pipeline recordings Follow-up to the pipeline recorder/player: asset nodes are now inspectable offline in the player, showing what each table held after the recorded run. At record finalization, for each ducklake/datatable asset in the pipeline the recorder samples the table (up to 100 rows + columns + row count) reusing the exact live-preview query path (loadAllTablesMetaData + getRows), so a replayed sample matches what the asset-detail pane would have shown. Captures are best-effort and per-asset — a missing/unconfigured table is stored as an error marker, never thrown, so the recording still completes. The player renders the sample as a read-only typed grid when an asset node is clicked (script nodes keep their logs/result/args detail). - recording/types.ts: PipelineAssetSample + assetSamples on PipelineRecording - recording/pipelineAssetSample.ts: capturePipelineAssetSample() helper - recording/pipelineRecording.svelte.ts: recordAssetSample() + assetSamples - recording/PipelineRecordingReplay.svelte: asset-node data-sample panel - pipeline/[folder]/+page.svelte: sample each asset in finalizePipelineRecording Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * recorder * feat(hub): record data pipelines in deploy-to-hub with interactive player Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hub): match editor cascade timeout, warn on cycles, reset badge on re-run Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): address review — finalize race, stale replay timers, /replay redirect, bounded sampling, jobs validation Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): structural recording validation, guard-clear + SSE cleanup on throw paths Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): validate nested graph arrays and timeline frame statuses Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hub): scope recording to bundle membership, fail cyclic runs, validate recording elements Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hub): prune recorded graph + asset samples to bundle membership Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): validate graph.triggers array and per-job initial_job/events shapes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): guard non-object payloads, event elements, and asset-sample/code maps Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): render error boundary + validate trigger_kind and non-empty sample error Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): validate event.data and recorded-job shapes for all replay types Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): make the replay event timer crash-proof against malformed events Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): await replay completion and boundary-wrap all three players Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(recording): guard flow Play handler, cap ?src= download size, trim comment Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
30eedf9ee1 |
feat: Add section to deploy projects to hub (#9332)
* feat: add Deploy to Hub workspace settings tab * Init record logic * Fix wordings * Add publish-app drawer with per-app rate limit mock - Publish drawer on raw_apps/apps exposes public URL, copy-iframe, unpublish - Inline per-app rate limit config (req/min, burst, per-IP toggle) - Rename workspace settings "Default app" tab header to "Apps" to cover both default app and public rate limiting Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Simplify publish drawer to show workspace-wide rate limit only Drop per-app rate limit fields (req/min, burst, per-IP) — none of these are supported by the backend. The drawer now shows the existing workspace-level rate limit read-only with a link to edit it in Workspace settings → Apps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Rename publish-app drawer wording to 'Share as iframe' 'Publish publicly' was ambiguous (publish to Hub vs make public URL). Use 'Share as iframe' for the button and drawer title, and 'Generate iframe' for the confirm action. Intro text now explicitly mentions iframe embedding use cases (Hub, docs page, own site). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Wire DeployToHub to real workspace data - Fetch apps, raw_apps, flows, scripts, resources via their services - Fetch workspace rate limit via WorkspaceService.getSettings - Share-as-iframe flips app policy.execution_mode to 'anonymous' via AppService.updateApp and resolves the real public URL via getPublicSecretOfApp + computeSecretUrl - Detect already-public apps from listApps execution_mode field - Filter out app_theme resources (noise, present in every workspace) - Hub bundle/version push and recording remain mocked (no backend yet) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Wire recordings to real jobs with run-preview UX - Recording flow now fetches the real schema, runs the job, and polls getCompletedJobResultMaybe to surface success/failure before saving. - Drawer shows a sticky status box (loader / success / failure) with a result preview, a job link, and an in-context Save CTA. - Only successful runs can be saved as a recording. Failures show the error and offer re-run. - Filter cache/state/app_theme internal resource types (mirrors workspaces_export.rs filter). - Added "What is a recording?" explainer banner above the items list. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Add draft/review state machine and submission gating - Phases: predeploy → draft → under_review → live, with workflow step indicator and contextual footer actions per phase - Bundle drawer collects name + readme before pushing the draft - draftItems snapshot frozen at deploy time; workspaceItems keep refreshing without affecting the draft - Folder MultiSelect lets users scope the bundle to one or more folders; empty = whole workspace - Submit-for-review disabled until every script and flow in the draft has a recording (progress bar + counter) - Recordings now run the real job and poll for success/failure; only successful runs can be saved - under_review phase locks editing, sharing, and recording - Dark mode variants on every coloured banner - Steps card shows the full 3-step process always, highlighting the current step Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Make recordings optional, encourage them for discoverability - Submit for review no longer gated on full recordings - Footer hint now frames recordings as boosting approval speed and public Hub featuring, not as a hard requirement - Progress card label switched from 'Recordings needed' to 'Recordings recommended' - Items without a recording display a yellow 'No recording' badge in every phase so the gap stays visible after submission Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Allow per-item selection inside the bundle scope - Items in predeploy now have checkboxes (all selected by default) - Select all / Deselect all act on the current folder filter - manualDeselected resets when the folder filter changes - Bundle button uses the selected count, disabled when zero - Draft snapshot keeps only the selected items - Checkboxes hidden in draft / under_review / live phases Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Add diff button once approved by admins * Small fix * Nits * fix(deploy-to-hub): paginate workspace list and cancel stale record polls - loadWorkspace fetches all pages instead of capping at 100 items per kind - pollJobUntilComplete now bails when recordRunSeq advances (new record target, re-run, or drawer close), preventing late completion of a previous run from overwriting current state Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * perf(deploy-to-hub): parallelize public-app URL resolution resolvePublicUrl now runs once per anonymous app via Promise.all instead of serially inside the items loop, removing N round-trips from initial tab load. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(indexer): tell admins when ingress routes search to wrong pod (#9274) * [ee] fix(indexer): tell admins when ingress routes search to wrong pod When the IndexReader is absent on the pod handling a search request but another pod is actively holding the indexer lock, the EE handler now returns a tailored error pointing at the ingress/load-balancer configuration instead of the generic "indexer not running" message. The indexer status endpoint reads the DB lock so it reports "running" from any pod, but search endpoints need the in-memory IndexReader that only exists on the lock holder. In multi-replica deployments this looks like the indexer is healthy but every search 404s. Companion: windmill-labs/windmill-ee-private#TBD Fixes WIN-1968. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to eb18d7b4c0e37fea3f6e1e2cc44e0fddd74ff817 This commit updates the EE repository reference after PR #586 was merged in windmill-ee-private. Previous ee-repo-ref: 7dd43d1850813071cc18ba49ba090583e7321f4b New ee-repo-ref: eb18d7b4c0e37fea3f6e1e2cc44e0fddd74ff817 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> * feat(cli): add `wmill init prompts` and custom override slot (#9266) * feat(cli): add `wmill init prompts` and custom override slot Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(cli): replace init prompts with refresh prompts + AGENTS.md/AGENTS.cli.md split Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(cli): dedupe claude skills via @-includes and add prompts freshness check Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(cli): drop migration-choice flags from `refresh prompts` Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(cli): add 'Running and previewing local changes' section to AGENTS.cli.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cli): write full skill content to .claude/, drop @-include wrapper Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(cli): reconcile CLAUDE.md the same way as AGENTS.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cli): address PR review nits — argv parsing, lazy import, comment detection, error propagation Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: add yolo mode for ai chat tools (#9258) * feat: add yolo mode for ai chat tools * nit * fix: align chat footer controls * feat: add ai chat autonomy modes * feat: add autonomy mode dropdown * fix: highlight yolo autonomy icon * fix: auto accept flow edits * fix: hide unsupported autonomy modes * fix: handle auto-accept flow editor races * fix(debugger): add non-root user support to Dockerfile (#9277) Mirrors the main Windmill Dockerfile pattern: creates a windmill user (UID/GID 1000) and makes cache/work directories world-writable so the image runs cleanly under Kubernetes securityContext.runAsNonRoot or runAsUser: 1000 without permission errors on Bun, pip, or windmill cache writes. Fixes WIN-1969 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(ai): enforce RLS and scope check on user-supplied X-Resource-Path (#9276) * fix(ai): enforce RLS and scope check on user-supplied X-Resource-Path The AI proxy handler accepts an X-Resource-Path header to override the configured workspace AI provider. When supplied, the handler loaded the resource value from the resource table using the root DB pool with no resources:read scope check, so any authenticated workspace user could point X-Resource-Path at a restricted AI resource (e.g. one in a folder they cannot read) and the proxy would use that resource's provider credentials for the outbound AI request. For user-supplied resource paths, now require resources:read:{path} scope and fetch the resource through user_db.begin(&authed) so RLS enforces the same folder/group boundary as the resource API. The RLS- scoped $var: resolution stays in place as defense in depth. The admin-configured workspace/instance ai_config path is unchanged. Fixes WIN-1971 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ai): regression test for X-Resource-Path RLS enforcement Cover all four cases: - non-admin pointing X-Resource-Path at a restricted resource is rejected - non-admin pointing it at a resource they own still works - admin can point it at any resource - workspace-configured proxy flow (no X-Resource-Path) is unchanged Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: add userdraft listing primitives (#9268) * feat: add userdraft listing primitives * fix: cancel stale userdraft discard writes * docs: remove global ai userdraft plan * feat(nsjail): optional disk-backed /tmp via instance setting (#9272) * feat(nsjail): optional disk-backed /tmp via instance setting * test(nsjail): unit-test tmp mount resolver and narrow visibility * refactor(nsjail): switch tmp backing to select + conditional UI * ui(nsjail): make tmpfs the visible default in /tmp backing select * fix(nsjail): refuse preexisting jail_tmp to block symlink escape * fix(nsjail): allow jail_tmp reuse on sequential nsjail calls Codex flagged that python/ruby/rust executors invoke nsjail twice per job_dir (install then run). The previous resolver treated any preexisting jail_tmp as hostile and silently fell back to tmpfs on the second call, so disk-backed mode never reached the main script run for those langs. Use symlink_metadata().is_dir() to distinguish a real directory left by an earlier call in the same job_dir (safe to reuse) from a symlink or other entity (still refused, as the codebase-tar escape requires). Also loosen the frontend visibility predicate: only hide nsjail settings when job_isolation is explicitly 'none' or 'unshare', so deployments that enable nsjail via DISABLE_NSJAIL=false with no DB setting can still see the controls. * chore(main): release 1.706.0 (#9270) * chore(main): release 1.706.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> * fix(nsjail): gate unix-symlink test behind cfg(unix) for Windows build (#9280) The disk_backed_refuses_preexisting_symlink_at_jail_tmp test calls std::os::unix::fs::symlink directly, which doesn't exist on Windows targets. Without a cfg gate, `cargo check --tests` fails on Windows with E0433. Other symlink call sites in this crate (php_executor, bun_executor, rust_executor, etc.) already follow this pattern. Fixes WIN-1972 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Reduce slim image vulnerability surface (#9279) * Reduce slim image vulnerability surface * chore(docker): drop apt-get upgrade -y from slim images apt-get upgrade hurts build reproducibility (same Dockerfile + same commit at different times produces divergent images) and trips hadolint DL3005. The freshness it buys is dominated by simply rebuilding against the periodically-refreshed debian:bookworm-slim base image. The --no-install-recommends and apt-list cleanup wins are kept. --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> * fix(git-sync): bump to hub/28234 with stateless gpg.program wrapper (WIN-1974) (#9282) * fix(git-sync): revert LATEST_GIT_SYNC_SCRIPT_PATH to hub/28230 to restore GPG-signed deploys (WIN-1974) hub/28231 (PR #9230) is the "thin" script that hands the actual `git commit` to the CLI's hidden `sync git-deploy`. The hub script still does the GPG setup (import key into a fresh GNUPGHOME, dummy `gpg -bsau` to warm the agent passphrase cache, then `git config user.signingkey` + `commit.gpgsign` locally), but the commit no longer runs in the same `git_push` flow — it runs minutes later inside the CLI after workspace API resolution, zip pull, file extraction, and lockfile autofill. By the time the spawned `git commit` asks gpg-agent for the cached passphrase, the cache state is no longer reliable (or the spawned `gpg` ends up talking to a fresh agent), so signing fails non-interactively with `gpg failed to sign the data`. hub/28230 is hub/28217's in-script logic rebuilt with windmill-cli@1.703.3: the GPG setup and the in-script `sh_run("git commit ...")` happen back-to-back in `git_push`, so the cache is always fresh. It preserves wm_deploy / fork branch behavior, the EE deployment-callback `main()` signature is unchanged, and the only min-version check in EE (`is_script_meets_min_version(28103)`) is comfortably below 28230 — so this revert is safe. Forward fix (separate PR): publish a new thin script that, alongside the existing GPG setup, writes a `gpg.program` wrapper using `--pinentry-mode loopback --passphrase-file` so signing is independent of the agent's cache state. Re-bump past 28231 then. Fixes WIN-1974 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(git-sync): check in source-of-truth for the next hub script (gpg.program wrapper) This is the script that will be published to hub.windmill.dev once verified on a customer GPG-signed deploy. It replaces hub/28231's agent-cache pre-warm (`gpg -bsau` with --passphrase) with a stateless gpg.program wrapper + chmod-600 passphrase file. Every git-invoked gpg call goes through the wrapper, which always uses --pinentry-mode loopback (and --passphrase-file when a passphrase exists). Signing no longer depends on gpg-agent having a cached passphrase by the time the CLI's `git commit` runs — which closes WIN-1974. Not wired in yet: LATEST_GIT_SYNC_SCRIPT_PATH stays on hub/28230 until this script is uploaded and the new hub id is known. This file is checked in so the diff is reviewable, future bumps have a source of truth, and a CLI regression test can `cat` it for fixture parity. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(frontend): skip format/pattern validation for $var/$res/$jsonvar references in ArgInput A resource field with a `pattern` constraint (e.g. the gpg_key.private_key field, whose pattern enforces a `-----BEGIN PGP PRIVATE KEY BLOCK-----` prefix) rejects values like `$var:u/me/gpg-private-key` with an "invalid format" error in the resource editor — even though `$var:`/`$res:`/`$jsonvar:` are placeholders the backend resolves at runtime, not the actual string that needs to match the regex. Bail out of all format/pattern checks (email, ipv4, ipv6, uuid, custom pattern) when the value is one of these references. Required/numeric bounds/array checks still apply since they're shape-level, not regex. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(git-sync): bump LATEST_GIT_SYNC_SCRIPT_PATH to hub/28234 (gpg.program-wrapper fix) hub/28234 is the forward fix for WIN-1974: replaces hub/28231's agent-cache pre-warm (which became stale by the time the CLI's `git commit` ran) with a stateless `gpg.program` wrapper that uses `--pinentry-mode loopback` (and `--passphrase-file` when a passphrase exists) on every gpg invocation. Bundled CLI is windmill-cli@1.705.0. Verified via reproducer at /tmp/git-sync-diff/test-gpg-fix.sh: deliberately killing gpg-agent between GPG setup and `git commit` reproduces the customer's `gpg failed to sign the data` error verbatim under the old flow, and the wrapper signs through it. Holds for passphrase-protected keys, split-subkey [C]+[S] layouts, and unprotected keys. Drops the local source-of-truth copy (`hub-scripts/`) — hub is canonical now that 28234 is published. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(git-sync): drop verbose comment above LATEST_GIT_SYNC_SCRIPT_PATH The git history (this PR) carries the why; the constant name + value carry the what. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(cli): wmill sync git-deploy stops committing; caller owns commit+push (#9284) Single contract for the deployment-callback path: the CLI does branch checkout + pull, the caller (hub script in production, test in test) does git add + commit + push. This restores the WIN-1974 invariant — GPG setup and `git commit` run back-to-back in the same process, so the agent's pre-warmed passphrase cache is still warm at sign time — without needing a `--skip-commit` flag for the hub case and a default "also-commit" for everything else. Same behavior in every call site. Changes: - sync.ts: drop the gitSyncDeployPush call from pull()'s deploy path (both the onlyCreateBranch fast-return and the post-pull commit). `gitSyncDeployPush` stays exported for any caller that wants the same commit/push semantics — just not invoked by the CLI subcommand. - gitsync_promotion.test.ts: e2e test now does its own git add + commit + push after `wmill sync git-deploy`, mirroring what the hub script does in production. Same regression coverage (wm_deploy branch created in Case A, main untouched; main updated in Case B, no new wm_deploy). CLI typecheck unchanged (two pre-existing TarAsZip errors at lines 2578/3307, present before this PR). All 743 unit tests still pass. The accompanying hub script (option-C — CLI for branch+pull, script for commit+push) lives at /tmp/git-sync-diff/sync-script-to-git-repo-windmill.option-C.ts. Once published, a follow-up bumps LATEST_GIT_SYNC_SCRIPT_PATH to its id. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * bump git sync to 28236 * fix: fork compare visibility for non-admins and stale-token superadmins (#9283) * fix: use fork-scoped authed for fork visibility in compare_workspaces * test: add EE end-to-end repro for fork rename visibility * chore: restore concurrency_locks sqlx cache lost in cleanup * test: add regression for stale-superadmin-token fork visibility bug * chore: update sqlx cache for new test queries * chore(main): release 1.706.1 (#9281) * chore(main): release 1.706.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> * feat: add wmill job rerun subcommand (#9275) * feat: add wmill job rerun subcommand * feat: add wmill job restart subcommand for flow restart-at-step * chore(system_prompts): point plugin skills sync at plugins/windmill/ (#9287) * chore(system_prompts): point plugin skills sync at plugins/windmill/ The plugin checkout's plugin folder is being renamed from `plugins/windmill-code-plugin/` to `plugins/windmill/` to shorten the slash-command namespace and align with the matching Cursor plugin layout. Paired with windmill-labs/windmill-claude-plugin#8. That PR must merge first so the next sync run finds the new folder. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(system_prompts): update plugin-dir example to plugins/windmill Co-authored-by: centdix <centdix@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: centdix <centdix@users.noreply.github.com> * fix(cli): wmill sync pull updates wmill-lock.yaml for raw apps (#9289) * fix: flow recording teardown crash + rename package to @windmill-labs/components (#9288) * fix: guard against null recording during FlowRecordingReplay teardown Navigating away from a flow recording inside a workspace file-tree view threw `TypeError: Cannot read properties of null (reading 'flow')` from FlowGraphViewer once during the teardown tick. Svelte 5 compiles child component props as live getters that close over `$$props.recording.flow`. When `recording` flips to null on the parent's navigation, an outer `{#if !recording?.flow}` doesn't stop those getters from firing one more time as derived effects re-evaluate before the unmount lands — so the getter dereferences null and throws. Fix at the two layers where the deref actually happens: - FlowRecordingReplay: use `recording?.flow` at the binding sites (FlowViewer + graph-snippet FlowGraphViewer) so the compiler emits an optional-chained getter, and guard the snippet branch with `{:else if recording?.flow}` so it doesn't mount when there's nothing to show. - FlowGraphViewer: finish the optional chaining the rest of the file already used everywhere else (`flow?.value?.skip_expr`, `flow?.value?.cache_ttl`, `flow?.schema`). When the upstream binding returns undefined during teardown, the graph degrades to an empty frame instead of crashing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: rename package to @windmill-labs/components - frontend/package.json: rename `windmill-components` → `@windmill-labs/components` - frontend/publish.sh: drop the in-place sed rename dance; the checked-in name now matches what's published, so `npm run package && npm publish` is enough - frontend/package-lock.json, system_prompts/auto-generated/prompts.d.ts: regenerated by `npm run package` under the new name Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(flows): restore Variables and Resources in flow editor prop picker (#9290) The design system overhaul in |