mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-05 16:02:24 +00:00
252ffd0401dee21c841b086007f92f7f1d09eeee
6798
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
252ffd0401 |
chore(main): release 1.762.1 (#10181)
* chore(main): release 1.762.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
c82056cfde |
fix(schedules): stop disabling schedules on transient push errors (#10179)
* fix(schedules): stop disabling schedules on transient push errors A scheduled flow whose next-occurrence push failed after retry exhaustion used to be disabled, killing a healthy schedule over a transient DB blip (pool contention, statement timeout). Now that the unarmed-schedule reconciler exists (#10174), transient failures no longer disable: the current occurrence runs to completion and the reconciler re-arms the next occurrence once this run leaves the queue. In the flow schedule-push path after retry exhaustion we now branch on the error: QuotaExceeded/NotFound still disable (the schedule's own fault, and rearm_schedule would otherwise leave them enabled-yet-unarmed forever), while transient errors are only reported and the flow continues. The previous iteration returned a SchedulePushZombieError to force a zombie restart; that is removed, because zombie detection cancels (does not restart) same-worker flows, so it would have lost the current run of a same-worker scheduled flow. The now-obsolete SchedulePushZombieError type and its catch in worker.rs are deleted. Fixes WIN-2198 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(schedules): back off and surface repeated reconciler re-arm failures The unarmed-schedule reconciler retried a schedule that could not be re-armed on every pass, forever, logging only to the server. With the flow schedule-push path no longer disabling on non-transient errors, a persistently-broken push (bad stored cron/timezone/args, lapsed license key) now stays enabled and would spin in that loop silently. The reconciler now tracks consecutive re-arm failures per schedule: exponential back-off (2, 4, 8, … passes, capped) between retries so a broken schedule is not hammered, and after 3 consecutive failures it surfaces the cause once (records schedule.error + raises a critical alert) without disabling. Both reset the moment the schedule re-arms, which also clears the recorded error. Verified end-to-end on a running server: a flow schedule with a corrupted cron stays enabled, retries back off, the error is surfaced after the third failure, and it re-arms and clears the error once the cron is fixed. Fixes WIN-2198 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
203f6c69dd |
fix(worker): gate ansible socket-dir name check to unix (#10180)
is_persistent_control_path_dir_name is only referenced from prepare_socket_root, which is #[cfg(unix)]. On Windows nothing used it, so -D dead-code failed the build. Gate the function and its unit test to unix, matching the reaping code they support. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
3ffce7e2cc |
chore(main): release 1.762.0 (#10175)
* chore(main): release 1.762.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
0b6bd376db |
ci: drop stale path_field_renames from mcp runner test constructor
#10176 removed `path_field_renames` from `EndpointTool`, while #10162 added a new `ep()` test constructor in runner.rs that still set it. Each passed CI against its own base, but together on main the test build fails with E0560. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
ae3d9ce2c0 |
fix(mcp): apply token scopes consistently across mcp endpoint tools (#10162)
* fix(mcp): apply token scopes consistently across mcp endpoint tools Endpoint-tool authorization is now shared between single- and multi-workspace modes, honors the token's script/flow path patterns for every path-taking tool, and the JWT minted for proxied endpoint calls carries scopes derived from the caller's own. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(mcp): review nits: restore create_http_request doc, reword comments Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d0aa7dca13 |
fix: parse all names in grouped go param declarations (#10165)
* fix: parse all names in grouped go param declarations Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: bump windmill-parser-wasm-go to 1.761.0 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7d2c5ceb0f |
fix(flows): make updateFlow body path optional so AI can update flows (#10176)
* fix(mcp): default a body field to its same-named path param so updateFlow works Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: trim mcp path-param fallback helper comment Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(mcp): keep path params un-mangled so update tools take plain `path` Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): default update_flow body path from URL via EditFlow Harmonizes updateFlow with the EditVariable/EditResource/EditApp convention: the flow to update is identified by the URL, so the body path is optional and only needed to rename. Fixes the 422 at the API layer for every client (MCP, the in-app AI chat, raw HTTP), not just the MCP tool schema. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(mcp): drop redundant body-path fallback now that the server defaults it Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: fix stale generator comment after removing mcp body-path fallback Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(flows): mark updateFlow body path optional in the openapi contract Adds an `EditFlow` schema (path optional) for the update route so the public contract matches the server; createFlow keeps `OpenFlowWPath` (path required). Also trims two test comments to record constraints rather than history. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2ff5a918d5 |
feat(worker-tags): add * fork marker to workspace-scoped custom tags (#10177)
* feat(worker-tags): add `*` fork marker to workspace-scoped custom tags Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(worker-tags): pin fork-marker tag admission through real lineage Also render WorkspaceMatcher in its authored form in the operator-facing "not in the allowed CUSTOM_TAGS" error, and correct the authorization note on workspace_with_fork_ancestors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(worker-tags): gate fork-lineage tag lookup on workspace membership exists_workers_with_tags is a global route whose workspace is a query param. Resolving its fork lineage for a caller who is not a member disclosed whether an arbitrary workspace descends from one named by a tag(parent*) rule. Require membership before the lineage lookup, and sharpen the workspace_with_fork_ancestors contract accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(sqlx): add offline cache for fork-marker test INSERT query The new test_fork_marker_tag_admission_through_lineage integration test inserts a fork workspace with a bind-parameterized query that had no cached entry, failing the SQLX_OFFLINE=true CI build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9762089fcb |
fix(schedules): re-arm enabled schedules left with no queued occurrence (#10174)
* fix(schedules): re-arm enabled schedules left with no queued occurrence * fix(schedules): lock schedule row while re-arming and report outcome * fix(schedules): make reconcile lock cancellation-safe, re-check armed under lock Address review feedback on the schedule reconciler: - Use a transaction-scoped advisory lock (pg_try_advisory_xact_lock) instead of a session-scoped one. monitor_db runs under a 600s timeout; on cancellation a session lock on a pooled connection would be stranded, wedging reconciliation on every replica. An xact lock releases when its transaction is dropped. - rearm_schedule re-checks for a queued occurrence under the row lock and returns NoOp if already armed, closing the scan→lock window that could double-push across a cron boundary. Add a regression test. - Make reconcile_unarmed_schedules private (its only caller is in monitor.rs) and document its system-only contract. - Log the disable only after the guarded UPDATE actually disables the schedule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(schedules): never disable from reconciliation and cap re-arms per pass --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
396fb1c475 |
feat(otel-tracing-proxy): trust internal endpoints with untrusted CAs (#10139)
* [ee] feat(otel-tracing-proxy): trust internal endpoints with untrusted CAs Add `insecure_upstream_hosts` and `upstream_ca_certs` to the HTTP Request Tracing settings so the OTEL tracing proxy can reach internal endpoints with untrusted or private-CA certificates while keeping them traced. Wires the two settings through the worker config and live reload, adds the inputs to the instance settings UI, and pulls in the rustls upstream-client deps (hyper-rustls/tokio-rustls/rustls/ rustls-native-certs/rustls-pemfile; hyper-http-proxy switched to its rustls feature). The proxy-side implementation lives in the companion EE PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: bump ee-repo-ref to otel_ca companion commit Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(otel-tracing-proxy): expose new fields in declarative config; bump ee-ref Addresses code-review findings: - Add `insecure_upstream_hosts` and `upstream_ca_certs` to the declarative `OtelTracingProxySettings` in instance_config.rs so operator/GitOps-managed installs can set them and reconciliation no longer drops values saved via the UI. - Restore the trailing newline on ee-repo-ref.txt and bump it to the companion EE commit carrying the strict host-matching / port-ordering fixes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 51e50629f48dbc4f5520a787b4bdfb76f4cd38d3 This commit updates the EE repository reference after PR #665 was merged in windmill-ee-private. Previous ee-repo-ref: 49f458e4446395e98915c220baa757ab3b2ed2d8 New ee-repo-ref: 51e50629f48dbc4f5520a787b4bdfb76f4cd38d3 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> |
||
|
|
97f4477069 |
feat(forks): let a fork's creator manage developers on it without being an admin (#10166)
* feat(forks): let a fork's creator manage developers on it without being an admin Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(forks): bind the fork-creator grant to the member's parent username and lock the delete Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
be57dd91e4 |
fix(ansible): keep persistent-connection socket path under the AF_UNIX limit (#10167)
* fix(ansible): keep persistent-connection socket path under the AF_UNIX limit Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): root socket dir at WINDMILL_DIR and verify we own it Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): fail closed on an untrusted socket root and honor commented section headers Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): validate the socket root after creating it, not before Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): root socket dir at sticky /tmp so the image's 0777 windmill dir cannot disable it Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): only sweep socket dirs the worker could have created Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): drop the configurable socket root, fixing its ancestor and sweep hazards Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): require the socket root be usable, not just safe Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ansible): do not override a control_path_dir the job set itself Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(ansible): drop the dead parent-creation step for the fixed /tmp root Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6131f7d2ae |
chore(main): release 1.761.0 (#10148)
* chore(main): release 1.761.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
91d6606868 |
fix(mcp): push granular scope patterns into SQL so scoped scripts/flows aren't truncated (#10140)
* fix(mcp): push granular scope patterns into SQL so scoped scripts/flows aren't truncated MCP `list_tools` fetched scripts/flows capped at the 100 newest by `created_at` and only *then* filtered by the token's granular folder/custom scope in Rust. In a workspace with more than 100 scripts/flows, in-scope items outside that newest-100 window were truncated before the scope filter ran, so a folder- or custom-scoped token could see zero tools even though matching items existed. Push the scope patterns into the query via a new `PathFilter::Patterns` (mirroring `is_resource_allowed`: `*` disables filtering, exact paths match by equality, `x/*` matches the folder or its subtree, empty grants nothing) so the filter applies before the `ITEMS_FETCH_MAX_LIMIT` cap. The existing hashed-name resolution path keeps its prefix behavior via `PathFilter::Prefix`, and the Rust post-filter stays as defense in depth. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(mcp): warn in scope selector when a scope exceeds the MCP tool cap The server exposes at most ITEMS_FETCH_MAX_LIMIT (100) scripts and 100 flows per token; a scope matching more silently drops the overflow, which bloats the assistant's context with a partial, arbitrary tool set. McpScopeSelector now computes how many scripts/flows the current scope would expose (per type, mirroring the backend's is_resource_allowed) and shows a warning Alert when either exceeds the cap, so the user can narrow the scope before generating the URL/token. An async sequence guard keeps rapid scope changes from applying stale counts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(mcp): address review — dedup count fetches, boundary-aware folder counting, fix copy Follow-up to the MCP scope-selector truncation warning: - Reuse a single per-type (scripts/flows) cache for both the preview list and the exposed count, instead of a second concurrent fetch of the same rows. - Count a folder scope against the `f/{folder}/*` subtree (via the same boundary-aware matcher), so a folder like `team` no longer over-counts a sibling like `team2` and falsely warns. - Custom-mode counts are derived synchronously from the already-loaded scripts/flows — no fetch. - Reword the warning to "most recent" (flows are ordered by edited_at, not created_at). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(mcp): anchor folder count fetch at the folder boundary Follow-up to review: the folder count fetched the unbounded prefix `f/{folder}` (backend `path LIKE 'f/{folder}%'`), so a prefix-sharing sibling like `f/team2` shared the page. With a page limit, enough newer sibling rows could fill the first page ahead of the target folder's older rows; the client-side boundary filter then dropped them all, wrongly suppressing the warning and emptying the preview. Fetch `f/{folder}/` instead so the backend prefix (`LIKE 'f/{folder}/%'`) is anchored at the folder boundary and never returns siblings. The client-side matcher stays as a backstop for folder names whose LIKE wildcards (`_`, `%`) can still let the backend prefix over-match. 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: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
4fc3f304c6 |
feat(forks): add "Hide unchanged drafts" toggle to fork deploy-draft tab (#10022)
A fork clones the parent workspace's drafts on creation, so the fork's Deploy-draft tab listed all of them as deployable even though the fork never touched them. Add a "Hide unchanged drafts" toggle (fork-only, on by default) that hides drafts identical to the parent's. Backend: the drafts-list endpoint accepts an optional `compare_to_workspace` (honored only when it is the workspace's actual parent) and flags each row with `unchanged_from_parent` via a jsonb-equality subquery against the parent's draft at the same (path, kind, owner). Frontend: the fork compare page passes its parent as the compare workspace; CompareDrafts renders the toggle and filters out unchanged rows, which also drops them from the selection/deploy count. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0e547adf23 |
fix(migrations): grant zombie_job_counter to windmill roles (#10159)
The zombie_job_counter table (20250205131522) was never granted explicitly to windmill_user / windmill_admin. The generic GRANT ALL ON ALL TABLES in 20250205131523 swallows failures via EXCEPTION WHEN OTHERS, and the ALTER DEFAULT PRIVILEGES it sets only covers objects created by that same role, so external-database deployments whose migration runner differs from the init-script runner leave the table ungranted. This stayed invisible while the table was only reached through ON DELETE CASCADE, which bypasses caller permissions. 20260625092813 replaced those cascades with explicit DELETEs in delete_jobs(), which run as the invoking role and fail with "permission denied for table zombie_job_counter". Same fix already applied to notify_event (20260619091631), script_trigger (20260619112847) and dispatch_event (20260701080313). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
51d8db6602 |
feat: automatic git-to-windmill sync (polling, webhooks, in-app PRs + checks) (#9552)
* docs: add design doc for automatic git-to-windmill pull sync
* docs: add migration plan and implementation phases to git-sync pull design
* feat(git-sync): add auto_pull settings schema and pull enqueue primitive
Adds AutoPullSettings/AutoPullMode/AutoPullStatus on GitRepositorySettings
(workspace_settings.git_sync JSONB), the GIT_SYNC_PULL_SCRIPT_PATH constant,
and should_pull/effective_poll_interval_s helpers with unit tests. Exports the
EE enqueue_git_pull_job primitive. Foundation for repo→Windmill auto-pull.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(git-sync): poll repos and auto-pull new commits into the workspace
Phase 1 of automatic repo → Windmill sync. A monitor task (EE-licensed,
single-replica via advisory lock) git ls-remotes each auto-pull-enabled
repository ~every minute and enqueues a pull when the tracked branch moves,
reusing the {workspace_id}:git_sync concurrency key so pulls serialize with
in-flight push commits.
- windmill-store: background (no-authed) resolver get_git_repo_head_for_autopull
that resolves the repo resource (incl. $var: refs) and ls-remotes; GitHub-App
repos are skipped here and will sync via webhooks (phase 2).
- monitor.rs: poll/reconcile/persist with optimistic sha advance and failure
status; targeted jsonb update so concurrent settings edits aren't clobbered.
- edit_git_sync_repository: preserve server-owned auto_pull state on UI save.
- openapi: AutoPullSettings/AutoPullMode/AutoPullStatus + auto_pull field.
- frontend: per-repo "Automatically deploy changes from Git" toggle with last
sync status; demote the GitHub Actions link to an advanced CI option.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(git-sync): wire webhook lifecycle + receiver; share reconcile logic
OSS side of phase 2 auto-pull webhooks:
- edit_git_sync_repository creates/removes the repo webhook on save (EE-gated,
best-effort → falls back to polling).
- monitor poller now delegates to the shared windmill_git_sync reconcile/persist
helpers (also used by the webhook receiver), removing duplicated logic.
- export the shared reconcile/persist/failure helpers; bump EE ref.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(git-sync): bump EE ref for phase 3 in-app PR creation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(git-sync): show webhook vs polling status on the auto-pull toggle
When a repo has an active webhook (auto_pull.webhook_id set), the status line
reads "instant via webhook"; otherwise it reads the ~1-minute polling cadence.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(git-sync): post PR diff check on dry-run completion (phase 4)
Worker completion hook in process_completed_job: when a DeploymentCallback job
carrying the __git_sync_pr_check marker finishes, parse the dry-run SyncResponse
and patch the GitHub check run with the diff summary (success/neutral/failure).
Export enqueue_git_pull_dry_run; bump EE ref.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(git-sync): bump EE ref (drop unused GHES webhook_secret)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* revert(git-sync): defer phase 4 PR diff checks (OSS side)
Remove the worker completion hook that posted the PR check run, drop the
enqueue_git_pull_dry_run re-export and the orphaned sqlx cache, bump EE ref.
Phases 1-3 (polling, webhooks, in-app PR creation) are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Revert "revert(git-sync): defer phase 4 PR diff checks (OSS side)"
This reverts commit
|
||
|
|
7d5009e392 |
fix: heartbeat job ping during s3object materialization in SQL executors (#10152)
* fix: heartbeat job ping during s3object materialization in SQL executors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KrFtZjXc8GB6VtSMVJFXjE * chore: update ee-repo-ref.txt Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KrFtZjXc8GB6VtSMVJFXjE * chore: update ee-repo-ref to e19948fa2974a7d89bec12957fc6d9fa0a421da8 This commit updates the EE repository reference after PR #668 was merged in windmill-ee-private. Previous ee-repo-ref: a3828dcd67f026c0e983a1a5dc5c5b33af3c3120 New ee-repo-ref: e19948fa2974a7d89bec12957fc6d9fa0a421da8 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
3bd9f05938 |
fix(alerts): identify server replica in low-disk alert + per-host dedup tag (#10143)
* fix(alerts): identify server replica in low-disk alert + per-host dedup tag The server-mode low-disk alert keyed its dedup tag on the mountpoint alone, so `simple_alert_helper` mapped every server replica onto a single alert row per mountpoint. With more than one replica that row flaps every monitor pass: a replica seeing low disk raises the alert while a replica seeing healthy disk recovers it. The alert text also could not say which replica tripped. The fix lives in windmill-ee-private (`low_disk_alerts` in windmill-common/src/ee.rs) and appends the hostname to both the message and the dedup tag, mirroring the worker branch. Also add a regression test pinning the server tag as per-host, and correct the monitor cadence comments: iterations are LISTEN_NEW_EVENTS_INTERVAL_SEC (10s by default), not 30s, so "~60s (2 iterations * 30s)" was wrong on both factors. * fix(alerts): widen healthchecks.check_type so per-host disk tags fit Alert tags embed a mountpoint and a hostname, both unbounded, but check_type was varchar(50). create_alert only logs the insert error while the notification still fires, so an overflowing tag re-alerts every monitor pass and never records recovery state. The server tag overflows for ordinary pod-length hostnames, and the existing worker tag already overflows for every tracked mount except "/". Widening the column fixes both; bounding the hostname would not, since the mountpoint alone can consume the budget. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to b3d01f2c0d2c0714ae95b8a348af22b0fcc30ee4 This commit updates the EE repository reference after PR #666 was merged in windmill-ee-private. Previous ee-repo-ref: ccd1e42cf6b2d051ca17074fbdf5b80a46cffe0f New ee-repo-ref: b3d01f2c0d2c0714ae95b8a348af22b0fcc30ee4 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
4e0fd4db55 |
feat(alerts): include disk total and top consumers in low-disk alert (#10144)
* feat(alerts): include disk total and top consumers in low-disk alert Point ee-repo-ref at the companion windmill-ee-private commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(alerts): pass alert message lazily from the min-version check simple_alert_helper now takes the error message as a future so callers can put diagnostic work behind it. Update this call site and point ee-repo-ref at the companion windmill-ee-private commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: point ee-repo-ref at rebased EE branch Rebase onto EE main so the pin keeps the SAML metadata fixes (394ad23) that the previous ref carried, and pick up the mount-scoped consumer walk. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: bump ee-repo-ref for bind-mounted file exclusion Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 4d7aafdba33a879b3c60d390c960e57679da9e87 This commit updates the EE repository reference after PR #667 was merged in windmill-ee-private. Previous ee-repo-ref: 08d3aa4c5bf630d15a28289cca62a0f1da7b7386 New ee-repo-ref: 4d7aafdba33a879b3c60d390c960e57679da9e87 Automated by sync-ee-ref workflow. * chore: point ee-repo-ref at the merged EE work plus the test fix ee#667 squash-merged, so the previous pin was a branch commit no longer reachable from EE main. Point at ee#669, which branches from EE main and carries the /proc test-portability fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to d8a7ac6ae97642a7f4928e6be6846a32dabf4e26 This commit updates the EE repository reference after PR #669 was merged in windmill-ee-private. Previous ee-repo-ref: 5526aedd73654b9aa4086dae0441b9687ff6415d New ee-repo-ref: d8a7ac6ae97642a7f4928e6be6846a32dabf4e26 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
a935d06c8e |
chore(main): release 1.760.1 (#10142)
* chore(main): release 1.760.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
8c725d9e44 |
fix(apps): honor presigned S3 signature on app display/preview routes (#10141)
The app provenance gate short-circuits on a valid presigned signature, but only the raw download_s3_file route parsed it. The parquet/csv/table-count/file-preview/metadata routes discarded sig/exp and always fell through to the provenance gate, so a presigned S3 object rendered as a table showed "File restricted" for any viewer who did not produce it. Thread sig/exp through every apps_u S3 display route and forward the presigned bearer from ParqetCsvTableRenderer/DisplayResult. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2092155191 |
chore(main): release 1.760.0 (#10128)
* chore(main): release 1.760.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
8bfe5c9340 |
fix(ai): stop sending the AI agent system prompt twice for OpenAI (#10126)
* fix(ai): stop sending the AI agent system prompt twice for OpenAI Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ai): document collect_system_prompt precedence and trim duplicate comments Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ai): hoist only the leading system prompt for OpenAI Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
17872018cc |
feat(nsjail): make python/ansible rlimit_as configurable per worker (GIT-921) (#10138)
nsjail caps a jailed job's virtual address space at rlimit_as (4096 MiB for python3 and ansible). JIT runtimes (Bun/JavaScriptCore, the JVM) reserve large virtual ranges up front, so a subprocess spawned from a jailed Python/Ansible job can crash against this cap even when its physical memory use is modest (e.g. the Bun-compiled claude CLI hitting JSC/pthread allocation failures). Most other language protos already run with disable_rl: true (unlimited); python3 and ansible are the outliers with an explicit rlimit_as. This exposes that cap via a per-language env var (NSJAIL_PY_RLIMIT_AS_MB, NSJAIL_ANSIBLE_RLIMIT_AS_MB) so operators can raise or lift it on a dedicated worker pool without a source patch/rebuild and without weakening the mount/PID/user-namespace isolation that provides the real security boundary. Only the address-space limit changes; cpu/fsize/nofile rlimits are untouched. Value is in MiB, or unlimited/none/inf/0 to uncap (rlimit_as_type: INF). Unset keeps the historical 4096 default. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f7eb5c460d |
fix(apps): invalidate cached app policy on change or deletion (GHSA-r5v4-cxh9-7qhq) (#10121)
* fix(apps): invalidate cached app policy on change or deletion (GHSA-r5v4-cxh9-7qhq) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(agents): keep PR tests and comments minimal and non-ephemeral Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
188647a942 |
fix(security): enforce variables:write scope on resource-delete var cascade (GHSA-xmr2-98m6-cjf7) (#10123)
A token scoped only to resources:write:<path> could delete linked secret variables it had no variables:write scope for, by embedding $var:<victim> in an attacker-controlled resource value and triggering the resource-delete cascade. #9712 re-enforced scoped-token boundaries broadly but missed this path. Add check_linked_var_delete_scopes, called before the cascade in both delete_resource and delete_resources_bulk: require variables:write for every linked variable, failing (and rolling back) the delete otherwise. No-op for unscoped tokens, so full-token cascade cleanup is unchanged. No co-located-path exemption: a resource and a variable may share a path, and a resource-write token can create a resource over an existing standalone variable and self-reference it, so "same path as the deleted resource" is attacker- forgeable and cannot stand in for variable scope. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6407d9ff5c |
fix(bash): normalize CRLF line endings before running scripts (#10131)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
27ead8d084 |
fix(ai): disable redirects on worker AI provider client (GHSA-5q4v) (#10122)
* fix(ai): disable redirects on worker AI provider client (GHSA-5q4v) The worker AI request path issued provider requests with the shared HTTP_CLIENT, which follows up to 10 redirects without revalidating each hop. SSRF validation on the provider base_url is single-shot, so a public base_url could 3xx the worker into a private/internal host (e.g. cloud metadata), bypassing the private-endpoint protection. The API proxy was already hardened in #9370; the worker path was missed. Add a dedicated AI_HTTP_CLIENT with redirects disabled and use it for the user-controlled provider endpoint, mirroring the API proxy client. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ai): add ALLOW_AI_BASE_URL_REDIRECTS debug escape hatch Off by default (redirects stay disabled). When set, restores redirect following on the AI HTTP client for debugging non-standard/self-hosted gateways, with a startup warning that it weakens SSRF protection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(ai): correct redirect comment for the escape hatch override Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(ai): condense redirect invariant comments per review Anchor the SSRF rationale to ALLOW_AI_BASE_URL_REDIRECTS (the knob that would break it) and shorten the AI_HTTP_CLIENT and call-site comments to avoid restating it at multiple sites (AGENTS.md). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
73c8d7f08a |
fix: reject git URL fragment/query SSRF bypass (GHSA-p5cj-8cfh-mjv6) (#10120)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
360e783b1d |
chore(main): release 1.759.0 (#10108)
* chore(main): release 1.759.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
6d1e12d5e9 |
feat(nativets): expose the standard web-platform globals deno_web provides (#10112)
* feat(nativets): expose standard web-platform globals for bun parity Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(nativets): wire bun-present Event subclasses and add construction smoke test Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(nativets): seed performance.timeOrigin per isolate, drop broken reportError Addresses CI Codex review on #10112: - performance.timeOrigin was undefined (setTimeOrigin never called); seed it per isolate via __wmInitPerIsolate executed from create_nativets_runtime. - reportError needs a global EventTarget this runtime never installs; drop it. - reword the namespace-import comment to not describe drafting history. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(nativets): wire DOMException global + broad edge-case smoke sweep DOMException is present in bun and, more importantly, deno_web references it as a global: AbortController.abort() with no reason constructs a DOMException("...", "AbortError"), so the already-wired AbortController/ AbortSignal threw "DOMException is not defined" on abort. Surfaced by a new functional edge-case sweep (smoke_web_globals_edge_cases) that exercises every wired global for real (not just presence) — DOMException/abort, AbortSignal.timeout, EventTarget dispatch, stream tee/reader/writer, all 3 compression formats, structuredClone Map/Set/Date/circular/reject-function, performance mark/measure, MessagePort delivery — plus a check that the merged Web Crypto globals still work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(nativets): restore arg-default smoke tests dropped in merge, drop history comments Addresses CI Codex/Pi review on the merge commit: - Merge conflict resolution (checkout --ours) dropped smoke_missing_optional_arg_uses_default and smoke_explicit_null_arg_is_preserved (added on main by #10111); restore them. - Reword edge-case-sweep comments to state the constraint, not how the gaps were found. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(nativets): give reportException a global dispatch target; wire stream reader/controller globals Addresses CI Codex review on #10112: - P1: a throwing EventTarget listener (and reportError) is routed through deno_web's reportException, which dispatches on a saved global reference. With none set, dispatchEvent threw a masking error that hid the original. Wire a dedicated EventTarget as that target so the ORIGINAL error is reported (async unhandled, matching bun). Does NOT make globalThis an EventTarget (bun's isn't either). Re-adds reportError, now functional. Regression test asserts the original error is surfaced, not a masking one. - P2: wire the stream reader/controller globals bun also exposes (ReadableStreamDefaultReader/BYOBReader, ReadableStreamDefault/ByteStreamController, ReadableStreamBYOBRequest, WritableStreamDefaultWriter/Controller, TransformStreamDefaultController) for instanceof parity; sweep verifies via real reader/writer/controller instances. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(nativets): make globalThis an EventTarget so globalThis.reportError() works Addresses follow-up CI Codex review on #10112: - P1: the prior fix saved a *separate* EventTarget as the global reference, so globalThis.reportError() still failed its receiver check (this === globalThis_) with 'Illegal invocation'. Make globalThis itself the saved reference by turning it into a functional EventTarget (setPrototypeOf to DedicatedWorkerGlobalScope + setEventTargetData + webidl brand + saveGlobalThisReference), per isolate in __wmInitPerIsolate. Both reportError(e) and globalThis.reportError(e) now surface the original error (async, matching bun) instead of throwing. New test smoke_report_error_both_call_forms covers both call forms. - P2: reword the regression-test comment to state the invariant, not the patch history. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(nativets): wire performance constructor globals for bun parity Addresses the P2 nit in the CI Codex review: bun exposes Performance, PerformanceEntry, PerformanceMark, and PerformanceMeasure as globals (deno_web exports all four), so wire them alongside the performance singleton. The edge-case sweep verifies instanceof against real mark/measure entries. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(nativets): state global-wiring comment as a constraint, not patch history Addresses the P2 in the CI Codex review: reword the block comment to describe the current bun-parity constraint and the deliberate EventSource/ImageData exclusions, without narrating what was or wasn't wired before (per AGENTS.md). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
95d9ff02ee |
fix(jseval): raise QuickJS eval memory cap to 128MB with clear OOM error (#10116)
* fix(jseval): raise QuickJS eval memory cap to 128MB with clear OOM error Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(jseval): note bare null/undefined throws are absorbed into OOM bucket Addresses CI review P2 nit on map_quickjs_error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(jseval): keep batch-rerun eval on a conservative 32MB cap; tighten OOM match Addresses CI review: eval_simple_js runs in the API process with unbounded request concurrency, so it must not inherit the raised flow-transform cap. Tighten the Exception OOM match to exact string. Reword drafting-history comments per AGENTS.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(jseval): gate OOM on InternalError kind; path-specific remediation hint Require the OOM InternalError name (not just the message) so a user throw new Error('out of memory') is not misclassified, and only suggest QUICKJS_MEMORY_LIMIT_MB on the env-tunable flow path (not the fixed-cap eval_simple_js path). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a6191e2a85 |
fix(mcp): advertise flow input variables in MCP tools (#10117)
Flow input schemas omit `required` (they carry an `order` key instead), which made `serde_json::from_str::<SchemaType>` fail in `convert_schema_to_schema_type`. The error was swallowed and callers fell back to an empty `SchemaType::default()`, so MCP flow tools advertised no inputs. Add `#[serde(default)]` to `type`, `properties`, and `required` on `SchemaType` so these schemas deserialize correctly. Scripts always include `required` and were unaffected. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e9fd4e7554 |
perf(rls): wrap session GUC reads in RLS policies for per-statement InitPlan (GIT-919) (#10110)
* perf(rls): wrap session GUC reads in RLS policies for per-statement InitPlan
RLS policies read current_setting('session.user' / 'session.groups' /
'session.pgroups' / 'session.folders_read' / 'session.folders_write')
directly inside their USING / WITH CHECK predicates. Postgres treats those
unwrapped calls as potentially row-varying and re-evaluates them once per
scanned row, on the read path of every workspace-scoped table.
The GUCs are set with SET LOCAL (set_config(..., true)) in
set_session_context(), so they are constant for the duration of a statement.
Wrapping each session-derived subexpression in a scalar sub-select lets the
planner hoist it to a one-time InitPlan (evaluated once per statement, reused
for every row) — same rows in, same rows out, N per-row GUC lookups collapse
to 1. Array-producing subexpressions keep an explicit ::text[] cast on the
sub-select so `= ANY (...)` / `?|` stay in their array-operand form rather
than being reparsed as a row-returning subquery.
The consolidating migration recreates every existing policy (across ~30 prior
migrations) whose predicate reads a session GUC, by deparsing the current
predicate and substituting the wrapped forms; the down migration is the exact
inverse (byte-identical round-trip). The adding-a-trigger skill documents the
wrapped form so new trigger tables inherit it.
Surfaced by pgrls (PERF001).
Fixes GIT-919
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(adding-a-trigger): fix RLS example cast placement for = any context
The `= any(...)` example put the ::text[] cast inside the sub-select, which
Postgres parses as a row-returning subquery and rejects at CREATE POLICY with
`operator does not exist: text = text[]`. Move the cast outside the sub-select
(matching the migration's canonical form) so the operand stays in array form,
and note why.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
ba232544e7 |
feat(nativets): add Web Crypto support via deno_crypto (#10109)
The nativets in-process runtime (deno_core) exposed no Web Crypto API:
`crypto` was undefined, so scripts could not use `crypto.getRandomValues`,
`crypto.randomUUID`, or `crypto.subtle`, even though the bun runner provides
them. This closes that parity gap by registering the `deno_crypto` extension
and wiring the crypto globals onto `globalThis`.
- Pin `deno_crypto = "0.223.0"`, the sibling release of the already-pinned
deno_core 0.352 / deno_web 0.240 stack (deps: deno_core ^0.352,
deno_web ^0.240, deno_error =0.6.1), so the rest of the deno stack is
untouched.
- Register `deno_crypto::init(None)` after `deno_web` in both the snapshot
(build.rs) and the runtime (lib.rs) extension lists, keeping the snapshot a
prefix of the runtime list. deno_crypto declares deps = [deno_webidl,
deno_web], which the position satisfies.
- Import `ext:deno_crypto/00_crypto.js` in runtime.js and assign
`crypto` / `Crypto` / `CryptoKey` / `SubtleCrypto` to `globalThis`.
- Add the `smoke_web_crypto` opt-in smoke test asserting the UUIDv4 shape of
`randomUUID`, a non-zero `getRandomValues` fill, and the known
SHA-256("abc") vector via `subtle.digest`.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
4917f79935 |
fix(mcp): let MCP tokens call preview run tools (jobs:run scope) — Fixes GIT-920 (#10107)
* fix(mcp): let MCP tokens call preview run tools (jobs:run scope) The MCP proxy mints an internal JWT scoped to exactly `scope_for_route` for the endpoint it forwards to. For preview run routes (`run/preview`, `run/preview_bundle`, `run/preview_flow`, `run_wait_result/preview`, `run_wait_result/preview_flow`), `determine_kind_from_route` matched the `SCRIPT_JOBS` prefix `jobs/run_wait_result/p` (because "preview" starts with "p") and derived `jobs:run:scripts`. But the preview handlers run arbitrary request-supplied code with no deployed path and require the broad `jobs:run` scope, so `jobs:run:scripts` was rejected with 403 "Required scope: jobs:run". Preview/bundle routes now carry no runnable kind, so the derived scope is the broad `jobs:run` the handlers expect. This also aligns the route-level access check with the handler check for these routes. Fixes GIT-920 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(mcp): anchor preview-route match to endpoint segment Address CI review: `route_path.contains("preview")` also matched by-path runs of a deployed runnable whose path contains "preview" (e.g. `jobs/run_wait_result/p/f/team/preview_report`). Since determine_kind_from_route also feeds check_route_access, such a route would derive the broad `jobs:run` and reject a legitimately kind-scoped `jobs:run:scripts:*`/`jobs:run:flows:*` token with 403. Anchor the exception to the actual preview endpoints (`jobs/run/preview*`, `jobs/run_wait_result/preview*`) so by-path runs keep their kind. Add regression tests for preview-named by-path paths, and trim the comments per AGENTS.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ba7f9c065f |
fix(nativets): apply parameter defaults for missing args instead of null (#10111)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
65d6f477ab |
chore(main): release 1.758.0 (#10084)
* chore(main): release 1.758.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
7ebfad382a |
feat(ai-agent): give tools a real description instead of the tool name (#10083)
* feat(ai-agent): use a real tool description instead of the tool name Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ai-agent): render tool-name error full width and hoist it above the description Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ai-agent): make tool description field hug its content so a single line is vertically centered Add an optional minHeight param to the autosize action (default unchanged at 30px) and pass minHeight 0 for the tool description so an empty/one-line field no longer reserves the 30px floor and leaves dead space below the text. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(ai-agent): regenerate OpenFlow-derived prompts, CLI guidance, and copilot zod schema for tool description Fixes the check-freshness CI failure (system_prompts + skills.gen.ts) and makes the flow copilot's openFlow.json / openFlowZod.gen.ts aware of the new AgentTool.description field so AI-authored tools can set 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> |
||
|
|
4edffeb84b |
fix(mcp): align script auto_kind filter with scripts list API (#10098)
The MCP `get_items` script filter used `auto_kind IS NULL`, which excluded every script with a non-null `auto_kind` (pipeline, test, WAC, ...). These are valid runnable scripts and should surface as MCP tools. Switch to the deny-list `(auto_kind IS NULL OR auto_kind <> 'lib')`, matching the scripts list API (windmill-api-scripts). Only library scripts (no main function) are excluded; pipeline/test/WAC and any future auto_kind values are included. Fixes WIN-2190 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1ffe5a1075 |
chore(main): release 1.757.0 (#10080)
* chore(main): release 1.757.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
851e30914e |
feat(saml): add ALLOW_PRIVATE_SAML_METADATA_URLS SSRF bypass (#10077)
* feat(saml): add ALLOW_PRIVATE_SAML_METADATA_URLS SSRF bypass Introduce the ALLOW_PRIVATE_SAML_METADATA_URLS env var and its allow_private_saml_metadata_urls() helper, mirroring the existing ALLOW_PRIVATE_MCP_SERVER_URLS opt-out. This lets self-hosted deployments with internal SAML IdPs (private IPs, no public DNS) skip the metadata-URL SSRF check that otherwise blocks server startup. The companion EE change (saml_ee.rs) consumes the helper to gate the validate_url_for_ssrf() call and additionally treats a cleared (empty/whitespace-only) SAML_METADATA setting as no SAML configured. Fixes WIN-2169 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(saml): surface opt-in hint and record SSRF control in threat model Add saml_ssrf_error_message() so private-IdP metadata URL rejections point to ALLOW_PRIVATE_SAML_METADATA_URLS (mirroring the MCP helper), with a unit test. Record the new SSRF opt-in under T2 in THREAT_MODEL.md, and bump the EE ref for the companion saml_ee.rs change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(saml): add validate_saml_metadata_url with opt-in unit tests Factor the SAML metadata SSRF gating into validate_saml_metadata_url() (mirroring validate_mcp_server_url) so the private-URL opt-in branch is unit-tested at the ssrf layer: blocks private by default, allows on true/1, and keeps scheme/host syntax guards when the opt-in is on. Bump the EE ref for the companion saml_ee.rs change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 394ad23242de429aef4074cc1dc28867dac95870 This commit updates the EE repository reference after PR #659 was merged in windmill-ee-private. Previous ee-repo-ref: 86da208c5aef2570568e18c7ab98f4d58adeec18 New ee-repo-ref: 394ad23242de429aef4074cc1dc28867dac95870 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> |
||
|
|
4f65187f9e |
chore(main): release 1.756.1 (#10072)
* chore(main): release 1.756.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
710a13a59d |
fix(apps): cover script/flow component outputs in deployed-app S3 provenance gate (#10070)
* fix(apps): cover script/flow component outputs in deployed-app S3 provenance gate Deployed apps read S3 files on-behalf of the app author for logged-in viewers (#10048). A confused-deputy guard confines those reads to files the app "produced", but the recent-production check only matched inline `appscript`/ `preview` jobs nested under the app path. Files produced by the deployed script/flow components an app is wired to run (e.g. a SQL query persisted to S3) were therefore denied "File restricted" for every viewer, admins included. Expand the provenance check to also match completed `script`/`flow`/`flowscript`/ `flownode` jobs whose `runnable_path` is one of the app's declared triggerables, and accept the author identity via `permissioned_as = on_behalf_of` (not only `created_by = caller`) so files produced on-behalf of the author are covered. Reads outside the app's declared triggerables stay denied. Adds a regression test seeding a script-kind produced file that reproduces the "File restricted" denial before the fix and passes after. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(apps): key S3 provenance on on-behalf identity + cover flow steps (review) Addresses the CI review on the S3 provenance gate: - P1 (confused deputy): the recent-production check keyed on `created_by = caller`, so a viewer who can run a declared script/flow directly (outside the app, with un-pinned inputs) could craft a result naming an author-only key and read it back through the app as the author. Key provenance instead on the producing job's `permissioned_as` matching the on-behalf identity the download reads as (the author in author-mode); a viewer's direct run has `permissioned_as = viewer` and no longer clears the gate. Drops `created_by` from both the appscript/preview and script/flow branches, closing the same latent hole in the pre-existing inline-script branch. - P2 (dead flow-step branch): `flowscript`/`flownode` jobs have `runnable_path = <flow_path>/<step_id>`, which exact `= ANY(...)` never matched. Split script vs flow triggerable paths; flow kinds now match the flow's own job (bare path) and its step jobs via a `<flow_path>/%` prefix, bounded to declared flows. - P2 (test realism): the regression test now uses the production component-prefixed triggerable key format (`<id>:script/...`), exercises a flow-step-produced key, and asserts a viewer's own direct run of a declared script stays denied (the P1 case). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(apps): tie deployed-app S3 provenance to an app-origination marker (review) Second CI-review round flagged that `permissioned_as` still does not prove a job was app-launched: a runnable configured with its own `on_behalf_of` makes a direct `/jobs/run` resolve `permissioned_as` to that identity (the app author), so a viewer with run access could execute a declared runnable directly, craft an S3 result, and read it back through the app. The flow-path `LIKE fp || '/%'` match also let `_`/`%` in a declared path admit unrelated flows. Introduce a real app-origination marker instead of inferring provenance: - Add `JobTriggerKind::App`; `execute_component` stamps every app-launched job with `trigger_kind = 'app'` + `trigger = <app path>`. A direct `/jobs/run` cannot set this, so it is the authoritative signal that a file was produced *by the app*. - The provenance gate's recent-production check collapses to `trigger_kind = 'app' AND trigger = <this app path>` (+ the 3h window and result containment). This drops the forgeable `created_by`/`permissioned_as`/ `runnable_path`/kind logic entirely and removes the `LIKE` wildcard issue. - Provenance is scoped to THIS app's path, so another app's jobs (even same author) do not authorize this app's reads. Regression test rewritten to the marker model: an app-produced key clears for viewer and admin; a direct run whose `permissioned_as` resolves to the author stays denied (the forgery); another app's output stays denied. Adds `app` to the OpenAPI JobTriggerKind enum. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(apps): assert execute_component stamps trigger_kind='app' at runtime Adds an end-to-end test that runs a real script component through the app runtime (`apps_u/execute_component`) and asserts the enqueued job carries the app-origination marker `trigger_kind = 'app'` + `trigger = <app path>` (not the runnable path). The provenance-gate tests seed the marker directly; this proves the runtime actually produces the exact marker the gate depends on. execute_component commits the job row and returns its id, so the assertion reads the row directly — no worker needed to run the job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(triggers): reject trigger_kind=app for suspended-job reassignment (review) `JobTriggerKind::App` (added for the app-origination S3 marker) became a valid value for the resume/cancel suspended-trigger routes, whose handler derives the table name `<kind>_trigger`. There is no `app_trigger` table, so both endpoints would fail with a missing-relation database error (500). Reject `App` in `get_suspended_trigger` alongside webhook/schedule so it returns a clean 400. Adds a regression test asserting the reassignment route returns 400 (not 500) for trigger_kind=app. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(apps): don't stamp app-origination marker on preview runs (review) The app-origination marker (trigger_kind='app') was stamped unconditionally, including preview mode. A preview lets a `jobs:run` caller supply arbitrary `raw_code` against ANY app path without that app's deployed policy (raw_code with no path/id skips all app authorization), so a preview returning `{"s3":"<author-only-key>"}` would forge the exact marker the S3 provenance gate trusts and read the victim app author's file. Gate the marker on `!is_preview`: only deployed, policy-checked executions are app-provenanced. Preview/editor S3 display does not rely on this marker (the editor routes reads through the force_viewer allowlist), so nothing legitimate regresses. Adds a regression test asserting a preview run's job is not stamped trigger_kind='app'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(apps): editor-authorize preview marker + per-viewer S3 provenance isolation (review) Closes the codex P1 (preview forgery) without breaking editor preview downloads, and adds cross-viewer isolation to the provenance gate. - Preview marker now requires app write: `execute_component` stamps the app-origination marker on a preview only when the caller can EDIT that app (`require_is_writer`), instead of never stamping previews. An app editor already wields the app's author identity (they can deploy a component that reads the same file), so marking their own preview is no escalation and keeps preview-produced S3 results downloadable in the editor; a `jobs:run`-only caller who cannot edit the app still cannot forge the marker. Deployed runs are unchanged (always marked). - Per-viewer isolation: the provenance gate now also requires `j.created_by = <this caller>`. The security boundary stays the un-forgeable `trigger_kind='app'` marker; `created_by` is an additional filter ANDed under it, so it only narrows — a viewer can only download keys their OWN app runs produced, not another viewer's result. Restores the per-caller scoping #10048 had, now safe on top of the marker. Tests: preview marked iff caller can edit the app; cross-viewer isolation (another viewer's app-marked key denied, no admin bypass); direct-run and other-app keys still denied; deployed run still stamped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(apps): require apps:write scope (not just writer ACL) to mark preview provenance (review) require_is_writer checks the user's underlying ACL but ignores token scopes, so a writer's token deliberately scoped to apps:run/apps:read/jobs:run but WITHOUT apps:write could still mark a preview and forge provenance — even though that token cannot deploy the app (update_app requires apps:write), breaking the "any marked caller can deploy equivalent code" rationale. Require BOTH apps:write:<path> scope (check_scopes) AND the writer ACL (require_is_writer) before stamping a preview's app-origination marker. Deployed runs unchanged. Adds a scope-restricted-writer token to the test (apps:run/read + jobs:run, no apps:write) and asserts its preview stays unmarked; retains the full-editor positive case and the non-editor negative case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(apps): never app-provenance preview runs; read editor S3 as the caller (review) Simplifies the preview handling: a preview executes as the *caller* (Viewer mode), never as the author, so its results must be read back as the caller — never author-mode — and must never carry the app-origination marker. This removes the whole `require_is_writer` / `apps:write` / `can_preserve_on_behalf_of` reasoning (which was also unsound: a writer's token or session may not be able to deploy a component running as the app's on-behalf identity, so marking their preview could still escalate). - Backend: mark the app-origination marker for deployed runs only (`!is_preview`). - Frontend: `getS3File` (AppImage/AppPdf/AppDownload) now routes editor/preview reads through the viewer-scoped `job_helpers/download_s3_file` endpoint (reads as the caller), matching what DisplayResult/ParqetCsvTableRenderer already do; only a deployed app view uses the provenance-gated `apps_u` endpoint. This is the path that previously relied on marking previews, so nothing regresses. Test: a preview is never app-provenanced (owner's own preview and a non-editor's both stay unmarked). Cross-viewer isolation, deployed marking, and the reassignment guard are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(apps): app components run on-behalf of the app, not the referenced runnable (review) Root-causes codex's on-behalf-preview finding: `execute_component` was overriding the app's resolved on-behalf identity with the referenced script/flow's OWN `on_behalf_of` (its `on_behalf_of_email`). That is wrong in the app context — the app's execution mode should govern: - A Viewer-mode app could execute a component AS the referenced runnable's on_behalf identity (privilege confusion / escalation), instead of as the viewer. - A preview would run as that identity rather than as the caller, so its S3 output could not be read back as the caller — the download-identity mismatch codex flagged. Always use the app-resolved identity (author in author-mode, caller in viewer/preview); a referenced runnable's own `on_behalf_of` no longer leaks into app execution. Direct `/jobs/run` still honors a runnable's `on_behalf_of` (unchanged). With this, previews always run as the caller, so reading editor/preview S3 as the caller (viewer-scoped `job_helpers`) is unconditionally correct. - Test: the deployed-component e2e now seeds the script with a distinct on_behalf and asserts the component job's `permissioned_as` is the app identity, not the script's. - Also reword the getS3File `configuration` param comment to describe current state only (AGENTS.md comment rule). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(apps): surface 'app' trigger kind in Runs UI; condense provenance comments (review) Addresses codex review nits: - Add `app` to `jobTriggerKinds`, `triggerIconMap` (LayoutDashboard), and `triggerDisplayNamesMap` so app-component jobs (which now carry `trigger_kind = 'app'`) are filterable in Runs and render their trigger info. - Condense the app-origination marker, on-behalf-identity, and provenance-gate comments to state each invariant once in <=4 lines at its relevant site (AGENTS.md comment rule). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
22b47c8823 |
chore(main): release 1.756.0 (#10062)
* chore(main): release 1.756.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |
||
|
|
29f4cd4b6f |
feat(triggers): serve binary HTTP-route responses via base64 transfer encoding (#10058)
Add an opt-in `wm_content_transfer_encoding: "base64"` field to the composite result. When set (together with `wm_content_type`), result_to_response decodes the string result into raw bytes before sending it, so sync HTTP routes/webhooks can return arbitrary binary payloads (PDFs, images, ...) with any content type — not just as base64 text or via object storage. Explicit and safe: the encoding is never guessed, invalid base64 is a hard error (no silent fallback to the encoded text), an unsupported encoding is rejected, and a transfer encoding without a content type is rejected. Existing string responses are unchanged. Closes #5986 |
||
|
|
92b7f375a9 |
fix: replicate all secrets on fork when external backend is configured (#10060)
* fix: replicate all secrets on fork with external backend (WIN-2161) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: add Azure KV fork secret-replication reproduction (WIN-2161) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: condense clone_variables invariant comment (WIN-2161) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: drive real create_fork handler in Azure KV repro (WIN-2161) Replace the windmill-common test that mirrored clone_variables' loop with an end-to-end test in windmill-api-integration-tests that exercises the real migration, create_fork and variable-read endpoints against a local Azure KV emulator. Verified it fails (404 "not found in Azure Key Vault") without the fix and passes with it; unique per-run ids keep it robust to the emulator's persistent state. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
1ed7fc066b |
chore(main): release 1.755.0 (#10041)
* chore(main): release 1.755.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> |