* test: isolate WAC v2 python test from test-thread stack overflow
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* ci: bump RUST_MIN_STACK to 4MB for backend tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: edit scopes on existing API tokens
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback on token scope edit
- add SECURITY DEFINER to notify_token_scopes_change so trigger fires under windmill_user/admin roles (cubic P1)
- drop banned $bindable(default) on optional props (CLAUDE.md): make ScopesPicker.value and EditTokenScopesModal.open required
- detect MCP only when *every* scope starts with mcp: so mixed/null-scope tokens fall back to standard picker without dropping non-mcp scopes
- audit log scope payload via serde_json instead of Rust {:?}
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 workspace-shared ui/ folder reusable across raw apps
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add shared ui/ drawer in raw app editor sidebar
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: forward workspace shared ui/ to raw app editor iframe
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* all
* all
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add delete_after_secs and sensitive_inputs to raw app policy
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: simplify sensitive toggle label
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: use tertiary text for sensitive toggle label
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: unset sensitive field when toggled off
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback
- plumb force_viewer_sensitive_inputs/delete_after_secs so editor preview
matches deployed-mode encryption
- reuse resolve_delete_after_secs helper for consistency with scripts/flows
- log+ignore schedule_job_deletion errors so a failed schedule doesn't
surface as an execute_component failure
- fix text-primay typo in CacheTtlPopup and DeleteAfterUsePopup
- tighten extraFields return type to Partial<Pick<...>>
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: set OTEL span status on failed jobs and add stderr severity toggle
Record otel.status_code=ERROR and otel.status_description on the job /
job_postprocessing tracing spans when a job fails, so OTel exporters
(Sentry, Honeycomb, Datadog) see the standard span-level failure signal
instead of just the success=false attribute. Description is truncated to
512 chars to keep span payloads bounded.
Add OtelSettings.stderr_default_severity instance setting (error | warn |
info | debug, default error) to let operators downgrade the OTEL severity
used for job stderr output. Python logging routes every record >= WARNING
to stderr, so the historical blind stderr->error mapping produces false
positives for scripts like dlt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref for stderr severity toggle
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: clarify OTEL span description for already-completed jobs
When handle_queued_job returns Ok(false) on Error::AlreadyCompleted
(another worker already finished the job during a race), the span
was labeled "job returned false" which is opaque to operators.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: parse Python logging severity from job stderr
Replace the global stderr_default_severity instance toggle with a
worker-side classifier that recognizes Python's canonical
basicConfig() format (LEVELNAME:logger.name:message) and emits the
corresponding tracing level. Lines that don't match keep the
historical tracing::error! fallback, so genuine failures still
surface and non-Python output is unaffected.
Removes StderrLogSeverity, STDERR_LOG_SEVERITY, and the
otel.stderr_default_severity field; adds
classify_python_logging_line in windmill-common.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: cover classify_python_logging_line + fix truncate_description doc
Add unit tests for the Python stderr-severity classifier and correct
the truncate_description docstring to say "bytes" (the cap is byte-
based, with UTF-8 boundary rounding for safety). Addresses Claude
review feedback on PR #8918.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: hugocasa <hugo@casademont.ch>
* feat: support S3Object input args in native SQL scripts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: review fixes from local-review
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* update parser
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: support restart from steps inside BranchOne, ForLoop, Subflow
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: preserve original job kind in nested restart, support expanded subflow steps
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: read selected iteration from graph state for nested ForLoop restart
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: iteration selectors per ForLoop in restart popup, more nested restart tests
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: extract useNestedRestartState composable
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: cover deployed-subflow + FlowDependencies path in nested restart
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update sqlx prepare cache
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: detect BranchOne/ForLoop ancestors inside expanded subflows for nested restart
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: hide restart button for non-restartable steps (parallel containers, untaken branches)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review feedback on nested restart PR
- preview FlowRestartButton: hide nested case (chain UUIDs aren't resolvable in
preview path; users can use the run page for nested restart instead)
- branchOneAncestorMatchesOriginal: be permissive when status isn't reachable
(don't hide the button for BranchOnes nested deeper than top-level)
- worker_flow.rs: apply nested_restart_payload swap on the is_simple ForLoop
fast path too, so simple iterations don't bypass restart spawn interception
- FlowStatusViewer: reset expandedSubflows cache on jobId change; drop
$bindable({}) banned pattern for the new prop
- API resolver: validate the leaf step exists before returning (fail-fast)
- doc fix: branch_or_iteration_n is 0-based, not 1-based
- selectedJobStepIsTopLevel reset on early-return in composable
- comment iterationCounts collision caveat
- new HTTP-level integration tests covering the API endpoint contract:
happy path (top-level + nested), unknown step, out-of-range iteration,
parallel-loop rejection
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* revert: remove unreachable nested-restart swap on is_simple ForLoop fast path
The swap is unreachable in valid flows: `is_simple_modules` requires the body
to be a single `script` / `rawscript` / `flowscript` (per `FlowModule::is_simple`),
none of which spawn flow-kind children. Any nested-restart chain targeting a
leaf inside such an iteration is rejected by the API at leaf validation. Even
if a chain reached the worker via `JobPayload::RawFlow.restarted_from`, the
resulting `RestartedFlow` would fail to push (script kind isn't a flow kind).
Replaced the swap with an explanatory comment so the next reader knows why
the symmetry with the non-simple path was deliberately not added.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: handle undefined expandedSubflows + tighten branchOne match check
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: split flow-dep job tx so subprocesses don't hold row locks
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: link flow version from run page to pinned flow viewer
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: time-out dep job phase 1/3 db ops and surface error on flow page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: dissolve dep_map in phase 1 and recheck flow version unconditionally
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address PR review — view-latest reload, decimal truncation, app version
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: keep dissolve in phase 3 for relative-import dep jobs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: trim verbose comments and refresh sqlx offline cache
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address cubic — propagate dissolve errors, include workspace in reload key
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(wac): recognize @workflow main, list WAC in scripts/list, run preprocessor
Three workflow-as-code bug fixes:
- #8945: Python WAC template with `@workflow async def main(...)` was not
detected as `auto_kind = "wac"`. The detection only ran when no `main`
function was found. Hoist the heuristic so it runs whether or not `main`
is the entrypoint.
- #8946: `scripts/list?kinds=script` filtered out WAC scripts because they
set `auto_kind = 'wac'` and the SQL hid everything that wasn't NULL.
Allow both NULL and 'wac' (still excluding 'lib' library scripts).
- #8947: Preprocessor functions defined alongside a WAC workflow were
ignored. Inject the preprocessor invocation into the Python WAC wrapper
so it runs before the workflow on the first iteration, then plumb the
preprocessed args through `handle_wac_v2_output` so inline child
re-runs see the post-preprocessor args via `checkpoint.input_args`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(wac): integration tests for #8946 (scripts/list) and #8947 (preprocessor)
- test_scripts_list_includes_wac: hit GET /scripts/list?kinds=script and
assert WAC scripts are in the response (would have failed pre-#8946 fix
because of the auto_kind IS NULL filter).
- test_python_wac_v2_with_preprocessor: deploy a Python WAC script with a
preprocessor, run with raw event args, assert the workflow saw the
preprocessed shape and v2_job.args/preprocessed were updated.
- New wac_preprocessor.sql fixture with auto_kind = 'wac' set explicitly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(wac): address PR review feedback
Five review fixes:
- python_executor.rs: WAC preprocessor now runs inside the wrapper's
`try:` block so failures route through the same `result.json` error
serializer as workflow failures. Switched async-coroutine handling
from deprecated `asyncio.get_event_loop().run_until_complete(...)` to
`asyncio.run(...)` (the recommended primitive on 3.10+).
- bun_executor.rs: when copying preprocessed args into
`checkpoint.input_args`, surface JSON parse failures via `?` instead
of silently coercing to `Value::Null` (which would persist a corrupted
arg into every child re-run). Also collapsed the redundant double
iteration into a single pass.
- windmill-api-scripts/scripts.rs: switched the runnable-script filter
from an allow-list (`auto_kind IS NULL OR = 'wac'`) to a deny-list
(`<> 'lib'`), so future `auto_kind` values aren't silently filtered
from triggers/dropdowns.
- windmill-parser-py: aligned the parser's WAC heuristic with the
runtime detector `is_wac_v2_py` — `@task` is now optional, matching
the runtime which says workflows that only use inline `step()` are
still WAC. Added a regression test `test_parse_python_wac_step_only`.
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(nativets): forward OTEL-prefixed console logs to tracing events
Nativets jobs run in-process and bypass the handle_child.rs stdout loop
where `OTEL: ` lines are turned into `tracing::event!` calls when
`OTEL_JOB_LOGS=true`. Apply the same prefix handling in the nativets
log receiver so `console.log("OTEL: ...")` reaches the OTEL exporter
like it does for other runtimes.
Moves `OTEL_JOB_LOGS` and `OTEL_PREFIX` into windmill-common so both
crates share the same definition.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(nativets): emit job_log tracing target so logs reach OTEL bridge
For non-native runtimes, `lines_to_stream` → `process_streaming_log_lines`
(EE) emits every stdout line as `tracing::info!(target: "windmill:job_log", ...)`,
which is picked up by the EE `LogContextBridge` and exported to OTEL
(the bridge's filter is `EnvFilter` only, not the targets filter that
drops `windmill:job_log` from stdout/file sinks).
Nativets delivers logs in-process via a channel, so it never goes
through that path and console.log output only reached the Windmill UI.
Emit the same `windmill:job_log` event per line from the nativets log
receiver.
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: cli diff & deploy no-op handling + promotion debouncing
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: bump ee-repo-ref
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to ed842061576c3ac9b9eb89bb87f6db5b67904474
This commit updates the EE repository reference after PR #551 was merged in windmill-ee-private.
Previous ee-repo-ref: 1210d9f63de8eea4c3a210a10c60fe6382df477b
New ee-repo-ref: ed842061576c3ac9b9eb89bb87f6db5b67904474
Automated by sync-ee-ref workflow.
* test(git-sync): e2e tests for promotion-mode debounce keys
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
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): non-interactive Slack connect/disconnect
Extract create_slack_workspace_artifacts / create_slack_instance_artifacts
from the browser OAuth callbacks and expose them via two new endpoints that
accept a pre-minted xoxb bot token:
- POST /w/{workspace}/workspaces/connect_slack (admin)
- POST /oauth/connect_slack_instance (super-admin)
Both produce bit-for-bit identical DB state to the UI browser flow.
Wire three CLI commands as thin wrappers:
- wmill workspace connect-slack
- wmill workspace disconnect-slack
- wmill instance connect-slack
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(cli): round-trip stability for workspace settings handlers
wmill sync push was destroying UI-configured error_handler/success_handler
state on every deploy. Two orthogonal bugs:
(a) pushWorkspaceSettings called editErrorHandler with `path: undefined`
when the YAML lacked the handler block, which the backend treats as a
clear — so syncing settings.yaml that didn't mention the handler wiped
the DB row. Fix: skip the call entirely when absent from YAML.
(b) edit_error_handler omitted muted_on_cancel / muted_on_user_path when
false, but the CLI always sends them, causing perpetual deepEqual
drift and a spurious editErrorHandler call on every sync push. Fix:
always persist both booleans.
migrateToGroupedFormat now preserves explicit `null` on
error_handler / success_handler as a "clear remote" signal distinct from
absence. Widen ErrorHandlerConfig | null / SuccessHandlerConfig | null to
make this explicit in the type.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(cli): sync support for workspace-level Slack OAuth override
Add slack_oauth_client_id and slack_oauth_client_secret to the v2 tarball
export and to pushWorkspaceSettings, so the workspace-level OAuth override
is now fully managed as code through settings.yaml.
Semantics:
- both defined and truthy → setWorkspaceSlackOauthConfig (upsert)
- both defined but falsy (e.g. empty strings) and remote has a value
→ deleteWorkspaceSlackOauthConfig
- either omitted → leave remote alone ("not managed by git")
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(cli): normalize workspace settings sync to "omit = clear"
Earlier commits on this branch introduced an "omit = keep" rule for
error_handler / success_handler / slack_oauth_client_{id,secret} that
diverged from every other workspace setting (webhook, deploy_to, etc. all
treat YAML as canonical: absence = clear). Normalize:
- v2 tarball always emits these 4 fields (null when remote is NULL) so
round-trip is bijective and settings.yaml is a complete snapshot.
- pushWorkspaceSettings drops the absent-from-YAML guards; YAML is
canonical. Absence and explicit null both clear the remote — same rule
as every other field.
- set_slack_oauth_config / delete_slack_oauth_config now fire
handle_deployment_metadata so UI mutations reach git-sync-enabled
workspaces' committed settings.yaml.
Policy for users: pull before push (same as every other setting). On first
post-upgrade pull, explicit `null` keys appear for any workspace whose
handlers / oauth override are unset — one-time YAML diff, no semantic
change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(cli): add unit + integration coverage for Slack settings sync
Unit tests (settings_unit.test.ts): cover migrateToGroupedFormat preserving
explicit `null` on error_handler / success_handler, and passthrough of
slack_oauth_client_id / _secret (both populated and null values).
Integration tests (slack_settings_sync.test.ts, skipped on CI per the same
convention as datatable_settings_sync.test.ts): exercise the full backend
via withTestBackend to verify
1. pull emits null for unset error_handler / success_handler /
slack_oauth_client_id / _secret;
2. round-trip with all-null handlers is idempotent;
3. push of populated slack_oauth_config upserts;
4. omitting the slack_oauth keys from YAML clears remote (universal
"omit = clear" rule);
5. explicit null error_handler in YAML clears remote;
6. round-trip preserves a populated error_handler exactly, including the
always-persisted muted_on_cancel / muted_on_user_path booleans.
Also feature-gates `use crate::oauth2_oss::workspace_connect_slack` and its
route registration behind `cfg(feature = "oauth2")`: the import caused a
build failure on subsets of the workspace without the oauth2 feature,
surfaced by the integration test harness.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: bump ee-repo-ref to 59b6123
Pins windmill-ee-private to the tip of branch alp/slack_cli, which
contains the companion EE changes (helper extraction, non-interactive
Slack connect handlers, git-sync for Slack settings mutations).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Update SQLx metadata
* chore: regenerate system prompts for new slack CLI commands
Captures the new workspace connect-slack, workspace disconnect-slack,
and instance connect-slack commands in the auto-generated files that
CI enforces via system_prompts/check-freshness.sh.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to b4a5ca11e3b96ff03793c2bd396dbc1fe6ea1022
This commit updates the EE repository reference after PR #550 was merged in windmill-ee-private.
Previous ee-repo-ref: d7e44d0519327ec9077625130365e887826f324b
New ee-repo-ref: b4a5ca11e3b96ff03793c2bd396dbc1fe6ea1022
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>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* [ee] refactor: remove force_branch from git sync settings
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: update ee-repo-ref to 680885a4e8c8de5185650cddeb56b926e722718f
This commit updates the EE repository reference after PR #549 was merged in windmill-ee-private.
Previous ee-repo-ref: 37fe2e1286a162119df885062e50461400631850
New ee-repo-ref: 680885a4e8c8de5185650cddeb56b926e722718f
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* feat: WM_TESTED_RUNNABLE env var + wildcards in test: annotation
Extends the CI test feature so a single test script can cover multiple
runnables and branch on which one triggered it.
- test: annotation now supports glob wildcards: `*` matches one path
segment, `**` matches any depth. A new `ci_test_path_matches` helper
in windmill-common compiles patterns to anchored regexes with a small
quick_cache LRU.
- New migration adds a Postgres GENERATED `has_wildcard` column + partial
index on ci_test_reference so exact-match lookups keep using the
primary index and only wildcard rows are scanned for regex matching.
- ci_test trigger query and the UI `ci_test_results` / `ci_test_results_batch`
endpoints split into exact + wildcard paths; the batch endpoint now
issues one query per distinct kind instead of one per item.
- Worker injects `WM_TESTED_RUNNABLE={kind}/{path}` into CI test jobs,
derived from the trigger metadata stored at push time.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: scope CI test job lookup by trigger + populate WM_TESTED_RUNNABLE in resource interpolation
Scope the ci_test_results LATERAL lookup by v2_job.trigger so multi-target
tests (via wildcards or multiple exact annotations) report the correct job
per target. Also pass the tested runnable through transform_json_value in
resources.rs for consistency with schedule_path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 489eb0d89702e5d1cc7c6e0f9ba9e0c8e5063741
This commit updates the EE repository reference after PR #546 was merged in windmill-ee-private.
Previous ee-repo-ref: e7534bcafcd8c27fcf870b2ea868e901b00b7960
New ee-repo-ref: 489eb0d89702e5d1cc7c6e0f9ba9e0c8e5063741
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>
* fix(autoscaling): return applied_at with UTC timezone in events API
autoscaling_event.applied_at is a naive TIMESTAMP column. Serializing as
NaiveDateTime produces an ISO string with no timezone, which the browser
parses as local time — for users west of UTC this lands in the future and
TimeAgo's Math.max(0, …) clamps every event to "0s ago".
Cast the column with AT TIME ZONE 'UTC' and type the field as DateTime<Utc>
so the response includes a Z suffix.
Also pulls in the EE count-distinct fix for native worker autoscaling.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 4128203739a973330599dacfb054203cf9832f3a
This commit updates the EE repository reference after PR #548 was merged in windmill-ee-private.
Previous ee-repo-ref: 32636bc3e3996101554d5ef504785346929a593b
New ee-repo-ref: 4128203739a973330599dacfb054203cf9832f3a
Automated by sync-ee-ref workflow.
* chore: bump ee-repo-ref for applied_at UTC insert fix
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
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>
* [ee] feat: add auto-login SSO provider instance setting
Adds an instance-level `auto_login_provider` setting that, when set to
an OAuth provider key (e.g. "okta") or "saml", causes the login page
to auto-redirect users to the configured SSO flow on mount.
Useful for orgs with a single SSO where the provider button grid adds
a pointless extra click.
- Backend: new global setting constant, read from DB in list_logins
handler and returned as the `auto_login` field in the response
- Frontend: Login.svelte auto-redirects in loadLogins() when the
configured provider is actually present in the response
- Escape hatch: `?no_sso=1` skips the auto-redirect and shows the
normal login form (admin fallback when SSO is broken)
- No redirect loop: if the `error` prop is set (SSO callback failed),
the redirect is skipped
- Admin UI: new text field under Auth/OAuth/SAML in instance settings
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: skip auto-redirect on /user/login page
Auto-redirect should only fire on embeds where the user did not
explicitly navigate to a login screen (public app popup, approval
pages). Visiting /user/login is an explicit sign-in action — often by
an admin who needs password fallback — so we must never hijack it.
Gate the logic on a new `autoRedirect` prop (default true). The main
login page passes `autoRedirect={false}`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to b7157d55fb9f8d8f7aeb7b1fb69bc935af895a2f
This commit updates the EE repository reference after PR #547 was merged in windmill-ee-private.
Previous ee-repo-ref: e32a48499d206a24e0c12817b465775321b0ee41
New ee-repo-ref: b7157d55fb9f8d8f7aeb7b1fb69bc935af895a2f
Automated by sync-ee-ref workflow.
* fix: handle popup-blocked auto-redirect in popup mode
When Login is embedded with popup=true (public app), auto-redirect
funnels through window.open() without a user gesture — browsers block
it by default, leaving the user stuck on "Signing you in…".
Detect window.open returning null, clean up listeners, reset
autoRedirecting so the provider button grid re-renders, and surface a
toast pointing users at the manual button. The grid click retains its
user gesture and passes the popup blocker.
Also extracts a redirectSaml() helper so the SAML auto-redirect path
and the SSO button click share the same logic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
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: add OTEL_HOST_NAME env override for host.name attribute
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to f6bc5647cc41ce348111f781b4a0db2153a28f8a
This commit updates the EE repository reference after PR #545 was merged in windmill-ee-private.
Previous ee-repo-ref: c92441ae0d6d8e89b48677db8cb6b78e5bdae2db
New ee-repo-ref: f6bc5647cc41ce348111f781b4a0db2153a28f8a
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>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* feat: add Azure Event Grid triggers (EE)
Introduces a new enterprise trigger kind `azure` that supports three
modes via a single unified trigger type:
- basic_push: Azure Event Grid basic — custom topics, system topics
(Storage, Resource Manager, Key Vault, etc.), domains (push only)
- namespace_push: Event Grid Namespace topics (CloudEvents over HTTP push)
- namespace_pull: Event Grid Namespace topics (HTTP pull with lock-token
ack/reject for dead-lettering)
Auth uses a Service Principal resource (tenant_id, client_id,
client_secret, subscription_id). Subscriptions are created in
CloudEvents 1.0 schema so the push webhook handler and the pull listener
share one payload parser.
Backend
- New crate `windmill-trigger-azure` (OSS stubs + EE impl symlinked from
windmill-ee-private)
- Migration `azure_trigger` table with CHECK constraints enforcing
mode/columns coherence
- `TriggerKind::Azure`, `JobTriggerKind::Azure`,
`DeployedObject::AzureTrigger` variants
- Push route `/api/azure/w/{workspace}/*path` handles classic
Event Grid SubscriptionValidation handshake and CloudEvents 1.0
abuse-protection OPTIONS handshake
- Optional inbound JWT validation (audience check only for v1)
- Feature flag `azure_trigger` propagated through windmill-api,
windmill-store (resource helper), and added to ee_core
Frontend
- `triggers/azure/` editor with mode toggle (basic/namespace-push/
namespace-pull) and per-mode config (topic ARM id / namespace +
topic name / subscription / filters / push auth / pull options)
- Registered in icon map, display names, save functions, badge,
wrapper, editor, add-trigger menu
OpenAPI
- `AzureTrigger`, `AzureTriggerData`, `AzureMode`,
`AzureSubscriptionMode`, `AzureDeliveryConfig`, `TestAzureConnection`
schemas; `/azure_triggers/*` endpoints; client regenerated
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to eaa7c3a9cb37a9ccc93f10a2535d929365acd2d8
This commit updates the EE repository reference after PR #541 was merged in windmill-ee-private.
Previous ee-repo-ref: 9689014e8c12c36c1059fd8fa5758d550b8b8bc9
New ee-repo-ref: eaa7c3a9cb37a9ccc93f10a2535d929365acd2d8
Automated by sync-ee-ref workflow.
* feat(azure-trigger): secret-auth push, ARM discovery, capture isolation, CLI + parity
Frontend:
- Split mode selector into Namespace/Basic + Pull/Push
- ARM resource dropdowns (namespaces, Basic topics, namespace topics)
populated from the service principal; cascade with stale-selection
reset on SP / edition change
- Remove stale authenticate toggle + audience input (server-managed
push_auth_config has replaced them)
- Azure listing page: "Create from template" button; "Also delete Azure
subscription" toggle in the delete modal; simplified trigger label
falling back to path
- AzureCapture.svelte: "Test subscription name" with -wm-capture suffix
- CompareWorkspaces.svelte: wire Azure for fork/compare
- Drop Trigger-deployed/event-loss warning (capture subscription is
isolated with -wm-capture)
Backend:
- Shared-secret push auth (see EE crate for detail)
- JSONB push_auth_config column (renamed from delivery_config), #[serde(skip)]
so clients/CLI/exports never see it
- Drop redundant enabled column; mode supersedes
- Azure capture infra: AzureTriggerConfig + set_azure_trigger_config +
azure_payload route + TriggerKind::Azure arm; PT15M queue TTL on
capture subscriptions so they bound storage after tab close
- Granular ACLs, users offboarding, trash, git-sync deployed-object:
all include azure_trigger
CLI:
- Add azure to TRIGGER_TYPES, pushObj dispatch, getTypeStrFromPath,
trigger commands (get/update/create/list/template), sync delete
switch + regex; e2e test for `trigger new --kind azure`
- system_prompts: SCHEMA_MAPPINGS + schema_names include AzureTrigger;
auto-generated/* regenerated
Skill:
- .claude/skills/adding-a-trigger/ checklist covering every file that
needs editing when wiring a new trigger type (learned from this PR)
ee-repo-ref bumped to b0e490cbf3724b7b64c6a5b010e3bdf24acd873c.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): ci — ShareModal Kind + regenerated system_prompts
- frontend/src/lib/components/ShareModal.svelte: add 'azure_trigger'
to the Kind type so the listing page's "Permissions" action compiles
(ts2345 — caught by npm_check on CI, missed by fast-check locally).
- system_prompts/auto-generated/: regenerate to drop the stale
delivery_config / AzureDeliveryConfig fields from the Azure schema
(check-freshness on CI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(azure-trigger): use workspace constant_time_eq crate
Drop hand-rolled constant-time compare in favour of the workspace
constant_time_eq crate (same one used by http_trigger_auth).
ee-repo-ref bumped to 9659382d47286e7f7f66d01b6f5dd8d4ed34848b.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): pass placeholder + disabled via inputProps
`TextInput`'s `placeholder` and `disabled` go through its `inputProps`
prop — CI's `npm run check` caught the stale top-level passing that
`npm run check:fast` missed. Align with the DefaultEmailConfigSection
pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): correct LATEST_GIT_SYNC_SCRIPT_PATH version to 28213
The hub deploy of the azure-aware sync-script is version 28213, not
28214. Backend was pinning a non-existent hub script, which broke the
git_sync_e2e suite (every deploy's sync step 404'd).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): add azure_triggers to token scope selector + skill
- windmill-api/src/token.rs: `build_trigger_scope_domains` was missing
`("azure_triggers", "Azure Event Grid")`, so the CreateToken UI's scope
selector didn't surface azure_triggers:read/write. Backend already had
`ScopeDomain::AzureTriggers` wired (scopes.rs), this just exposes it.
- .claude/skills/adding-a-trigger/SKILL.md: capture both scope-related
files under the hardcoded-arrays section so future triggers don't miss
the UI surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(adding-a-trigger-skill): clarify token.rs scope effect
Not a regression — nothing was working before. Skipping TRIGGER_DOMAINS
just means the scope works via API/CLI but has no UI checkbox.
* docs(adding-a-trigger-skill): trim token.rs bullet
* fix(azure-trigger): regen openapi-deref + swap textarea for TextInput
- Run build_openapi.sh to regenerate openapi-deref.{yaml,json} with the
12 azure_triggers paths + schemas. These files are served by the
runtime (include_str! in windmill-api/src/lib.rs) to external SDK
consumers; without this regen the new endpoints wouldn't be advertised.
- Replace the raw <textarea> for event type filters with the
design-system TextInput in textarea mode (frontend/CLAUDE.md bans raw
HTML elements).
Addresses cubic + claude PR review items.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
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>
* fix: load job metadata on approval page via approval token
The approval page polled getJob without auth, which 400s for non-anonymous
jobs. The page swallowed the error so approvers saw the form but no flow
args, metadata, or graph. Accept the existing approval token on getJob and
skip the non-anon-user check when it validates against the job's flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(approval): address review feedback
- Validate approval token against URL job id directly before resolving
the parent flow, saving a DB roundtrip on the happy path (approval URLs
always carry the flow id).
- Request getJob with no_code/no_logs from the approval page so a
token-bearer only sees what the UI renders (args, raw_flow, metadata).
- Tighten OpenAPI description for the approval_token query param.
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 ai agent chat output flag
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: suppress ai agent tool chat messages
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: rename ai agent conversation output flag
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: expose ai agent conversation output toggle
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: gate ai agent chat tab by chat mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: regenerate system prompts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address ai agent chat review feedback
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Previously each API replica generated a random Ed25519 signing key at
startup (unless DEBUG_SIGNING_KEY_SEED was set). In multi-replica
deployments this caused "Invalid JWT signature" rejections in the
multiplayer server: the browser could sign a token on pod A while
`windmill-extra` had cached the JWKS public key from pod B.
Derive the seed deterministically from the DB-backed JWT_SECRET using
SHA-256 with a domain-separation tag so all pods agree without
coordination. Re-derive on JWT_SECRET rotation. The
DEBUG_SIGNING_KEY_SEED env var is still honored as an override.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: support windmill chat answer override
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: remove output fallback from chat override
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: handle non-string chat answer overrides
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: persist powershell workspace deps in deployed script lock
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: trigger dep job for powershell scripts on deploy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
A BranchOne predicate expression that threw was propagated as a
flow-level error, bypassing the flow's failure_module — especially
silent when nested inside a forloop with skip_failures: true, where
the failed iteration was swallowed with no handler ever invoked.
Catch the predicate-eval error inside compute_next_flow_transform's
BranchOne case, return a new NextFlowTransform::StepFailure variant,
and have push_next_flow_job route it through
update_flow_status_after_job_completion with success=false. Predicate
errors now behave exactly like a failing script step: failure_module
runs when defined, skip_failures still skips, workspace error handler
fires when the flow fails.
Closes#8889
* fix: add flow conversation token scope
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: make flow conversations scope plural
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: update flow chat service import
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: create windmill-ai crate and move base AI types from windmill-common
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: move worker AI types to windmill-ai crate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: move QueryBuilder trait and StreamEventSink abstraction to windmill-ai
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add base64 dependency to windmill-ai for bedrock PDF support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add windmill-ai refactor plan
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: address PR review — remove dead bedrock feature, add boxed_sink helper, move plan to docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: detect and clearly label OOM in zombie flow alerts
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review feedback on zombie flow OOM detection
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: track dollar-quoted strings in SQL block splitter
Queries like `CREATE FUNCTION ... AS $$ ... ; ... $$ LANGUAGE plpgsql;`
were being shredded on every `;` inside the function body because the
SQL splitter's state machine didn't recognize PostgreSQL dollar-quoted
strings. Add an `InDollarQuote(tag)` state so `$$ ... $$` and
`$tag$ ... $tag$` regions are treated as a single quoted span.
Opt-in via a new `track_dollar_quotes` flag on `parse_sql_blocks`;
enabled for PostgreSQL and DuckDB, disabled for MySQL/Oracle/BigQuery/
Snowflake which don't support the syntax.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: make windmill-parser-wasm a self-contained workspace
The wasm parser crate is excluded from the backend workspace (its
nightly-only `cargo-features = ["panic-immediate-abort"]` would break
stable cargo on the whole workspace), but its manifest still used
`.workspace = true` inheritance — which fails with "failed to find a
workspace root" once the parent no longer considers it a member.
Declare the crate as its own workspace by adding `[workspace]`,
`[workspace.package]`, and `[workspace.dependencies]` tables. Mirror
the relevant entries from the parent `backend/Cargo.toml` (same
version specs, same path targets) so resolution stays byte-identical
to what the parent would have produced.
Also:
- Teach `.github/change-versions.sh` (+ mac variant) to update this
crate's own `Cargo.toml` version and bulk-bump the `windmill-*`
entries in its `Cargo.lock` on each release.
- Bump the frontend's pinned `windmill-parser-wasm-regex` to 1.688.0
to match the freshly-built package, and refresh `package-lock.json`.
- Regenerate the wasm crate's `Cargo.lock` from scratch (first build
under the new workspace re-resolves the full graph; target-gated
deps from sibling crates like `windmill-parser-py-imports` are
now recorded in the lockfile but not compiled when targeting
wasm32).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extract the MSSQL s3 ingest+upload logging pattern into a reusable
`s3_stream_and_upload_with_logs` helper and apply it to the PostgreSQL,
MySQL, OracleDB, BigQuery, and Snowflake executors. Each s3 streamed
query now emits periodic progress lines, an ingest-done line, and an
upload+transcode-done line to the job output, matching MSSQL.
`convert_json_line_stream` now returns `BoxStream<'static, _>` so the
output stream can be forwarded to `s3.upload` from inside the generic
helper without lifetime gymnastics; the two existing callers already
boxed the result, so behavior is unchanged.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add proxy transport for ai evals
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: strip propertyNames for gemini schemas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: require explicit eval transport
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: async dep endpoints and queue-position logs in cli
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: share logQueueStatus between dev.ts and job_polling.ts
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: continue polling on transient errors in job_polling.ts
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>