Compare commits

...

55 Commits

Author SHA1 Message Date
windmill-internal-app[bot]
f927f46d8a chore: update ee-repo-ref to bcf3ceab92be635e65f59c0ca0e3c64d8c2f6928
This commit updates the EE repository reference after PR #389 was merged in windmill-ee-private.

Previous ee-repo-ref: fe74559f3d999b42be19284b2caa8cf9efce4694

New ee-repo-ref: bcf3ceab92be635e65f59c0ca0e3c64d8c2f6928

Automated by sync-ee-ref workflow.
2026-01-26 17:33:19 +00:00
Alexander Petric
d5cdc34252 Merge branch 'main' into alp/gh_app_timeout 2026-01-26 11:51:02 -05:00
Alexander Petric
59fba7eaf6 fix: gh app token check 5s connect 20s request timeout 2026-01-26 16:50:32 +00:00
dieriba
6418c4bcc6 feat: nextcloud native triggers (#6797) 2026-01-26 16:49:52 +00:00
Ruben Fiszel
f495cebd7d chore(main): release 1.615.3 (#7687)
* chore(main): release 1.615.3

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-01-26 16:08:16 +00:00
Ruben Fiszel
95e5d7e469 fix: change min worker version to 1.420.0 2026-01-26 16:02:20 +00:00
Ruben Fiszel
7191426ea2 chore(main): release 1.615.2 (#7685)
* chore(main): release 1.615.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-01-26 15:54:43 +00:00
Ruben Fiszel
1ac57589cf change min to 1,580,0 2026-01-26 15:53:50 +00:00
Pyra
1ae157dadd fix: mixed version error (#7686)
* fix mixed version error

Signed-off-by: pyranota <pyra@duck.com>

* fix comp error

Signed-off-by: pyranota <pyra@duck.com>

* fix

Signed-off-by: pyranota <pyra@duck.com>

---------

Signed-off-by: pyranota <pyra@duck.com>
2026-01-26 15:49:31 +00:00
Ruben Fiszel
f880655e32 fix: set 3.12 as python fallback if no version explicitely set 2026-01-26 15:15:48 +00:00
Ruben Fiszel
5e56d751f3 fix: add SSL_CERT_FILE to python install 2026-01-26 14:30:45 +00:00
Ruben Fiszel
0afc6bc46e chore(main): release 1.615.1 (#7684)
* chore(main): release 1.615.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-01-26 13:20:46 +00:00
centdix
29b274a08a fix(aiagent): fix usage for gemini 3 models (#7682)
* fix for gemini3 models

* cleaning

* cleaning

* small opti
2026-01-26 13:15:18 +00:00
centdix
fed90808ff rm manifest (#7683) 2026-01-26 12:59:45 +00:00
Ruben Fiszel
ac56ffe052 chore(main): release 1.615.0 (#7674)
* chore(main): release 1.615.0

* Apply automatic changes

* pin rdkafka

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-01-26 11:41:33 +00:00
Ruben Fiszel
345d52cf11 better sse break 2026-01-26 11:21:03 +00:00
centdix
5be3feaaa2 fix(aiagent) break on consecutive errrors (#7681) 2026-01-26 11:18:43 +00:00
centdix
2553d987d9 feat(ai): native bedrock compatibility (#7668)
* check endpoint

* use flag for cred check on worker

* use sdk for auth chat side

* cleaning

* cleaning

* also handle GET

* Add session token support in BedrockClient::from_credentials

Users with temporary STS credentials need session tokens for AWS
authentication. This adds the optional session_token parameter to
support these use cases.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Cache AWS SDK config loading to avoid repeated I/O

aws_config::load_defaults() performs environment variable lookups and
potentially file I/O on each call. Cache the result in a static OnceCell
to improve performance on high-frequency Bedrock requests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add debouncing to Bedrock credential check button

Prevent rapid clicks from spawning multiple concurrent flow preview
jobs for the worker credential check.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove orphaned SigV4 signing comment

The manual SigV4 signing code was removed in favor of the AWS SDK,
but this documentation comment was left behind.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove verbose tracing info and change-related comments

- Remove per-request auth method info logs (too verbose for production)
- Simplify from_env log to single debug-level message
- Remove comments describing future changes rather than current behavior

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* cleaning

* Fix Bedrock feature flag compilation warnings

Gate AWS-specific imports, struct fields, and methods behind the bedrock
feature flag to eliminate dead code warnings when building without the
bedrock feature enabled.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* bedrock flag

* cleaning

* Move BedrockCredentialsCheck from edit drawer to add drawer

The component was incorrectly shown when editing resources instead of
when adding new ones. Moved it from ResourceEditor.svelte to
ApiConnectForm.svelte.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* cleaning

* cleaning

* make aws-config optional

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-01-26 11:04:14 +00:00
Ruben Fiszel
5de8ecacdf fix integ tests 2026-01-26 10:51:32 +00:00
Ruben Fiszel
a7ee58095c fix build 2026-01-26 09:25:41 +00:00
Ruben Fiszel
2df369d141 add back deps 2026-01-26 08:55:17 +00:00
Ruben Fiszel
e2fdfb9765 pin rdkafka 2026-01-26 08:22:54 +00:00
Ruben Fiszel
0b6100c8b2 clean up cargo + update rmcp 2026-01-26 08:04:17 +00:00
Ruben Fiszel
bb9adca38f fix: update rmcp type aliases to non-deprecated versions
Renamed deprecated type aliases following rmcp library update:
- CallToolRequestParam → CallToolRequestParams
- InitializeRequestParam → InitializeRequestParams
- PaginatedRequestParam → PaginatedRequestParams

Also added required `meta` field to ClientInfo and CallToolRequestParams.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 08:03:20 +00:00
Ruben Fiszel
22ea61207a fix: make DateInput reactive to external value changes and handle empty dateFormat
- Convert to Svelte 5 syntax with $props(), $bindable(), $derived()
- Add $derived() to recompute date when value changes externally
- Handle empty string dateFormat by falling back to default
- Remove sendUserToast from derived computation (caused state mutation error)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 00:18:26 +00:00
Ruben Fiszel
522fa98d71 fix: allow SERVER_BIND_ADDR to override worker bind address
SERVER_BIND_ADDR now works for both server and worker modes with
different defaults: 0.0.0.0 for server/indexer/mcp, 127.0.0.1 for workers.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 23:52:49 +00:00
Ruben Fiszel
70efcbff49 update git sync version to 1.614.1 2026-01-25 23:45:03 +00:00
Ruben Fiszel
35081ca9d2 fix: persist "Planned later" and "Schedule" toggles in localStorage on runs page
The toggle states are now saved to localStorage and restored when
navigating back to the runs page, providing a consistent user experience.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 23:42:22 +00:00
Ruben Fiszel
865ab70c89 add comprehensive permissions tests and restrict operator script archiving
- Add permissions test suite covering scripts, flows, apps, resources,
  variables, schedules, and folder-based permissions
- Add test for operator restrictions (cannot create/update/archive)
- Restrict operators from archiving scripts (archive_script_by_path,
  archive_script_by_hash) for security consistency with flows/apps

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 23:33:54 +00:00
Ruben Fiszel
181e68d266 refactor: replace v2 live migration with regular SQL migration (#7678)
* refactor: replace v2 live migration with regular SQL migration

Remove the v2_finalize live migration that waited for workers to reach
v1.461+ and replace it with an idempotent SQL migration. Since enough
time has passed, all deployments are assumed to be on v1.461+.

Changes:
- Remove v2_finalize() function and spawn task from live_migrations.rs
- Remove MIN_VERSION_IS_AT_LEAST_1_461 constant from min_version.rs
- Add 20260125000000_v2_finalize.up.sql with all finalization steps
- All SQL operations use IF EXISTS/CASCADE for idempotency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: remove migration-related delays and tighten CLI tests CI trigger

- Remove 5s backend initialization delay in cargo_backend.ts that was
  needed for the v2 live migration (now replaced with SQL migration)
- Restrict CLI tests workflow to only trigger on cli/** changes
  (removed backend/**, openapi.yaml, openflow.openapi.yaml paths)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: skip v2_finalize migration if live migration already ran

Wrap migration in DO block that checks for 'v2_finalize_job_completed'
in windmill_migrations table. If present (live migration already ran),
skip entirely to avoid unnecessary table locks on upgraded instances.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 22:32:21 +00:00
Ruben Fiszel
a22d179903 add GitHub Actions CI and raw app sync tests (#7677)
* feat(cli): add GitHub Actions CI and raw app sync tests

- Add CLI tests GitHub Action that runs on Linux and Windows
- Add build check job that runs on CLI and openapi.yaml changes
- Uses Rust cargo backend instead of Docker for better CI compatibility
- Add cargo_backend.ts and test_backend.ts for test infrastructure
- Fix Windows path separator bug in raw_apps.ts (use "/" for relative paths)
- Fix PostgreSQL URL parsing in cargo_backend.ts
- Update tests to use gitBranches format instead of deprecated overrides
- Add raw_app_sync.test.ts for raw app sync workflow testing (ignored for now - needs EE)
- Skip tests that require EE features (git sync settings, raw apps)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): Fix Windows path compatibility issues in tests

- Use fromFileUrl() in cargo_backend.ts for proper Windows path handling
- Normalize path separators to forward slashes in resource_folders.ts
- Fix readDirRecursive to return normalized paths in test helper
- Use forward slashes consistently in buildMetadataPath and detection functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): Use SEP in test assertions instead of modifying logic

- Revert resource_folders.ts to use SEP as intended
- Update test assertions to use SEP for platform-specific paths
- Keep readDirRecursive normalization for consistent test comparisons

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): Use SEP for all path separators in test assertions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): Use resolve() for proper cross-platform path handling in cargo_backend

String concatenation with path separators creates malformed paths on Windows.
Use path.resolve() instead for proper cross-platform path resolution.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(backend): Add cfg attributes for Windows compatibility

- Add #[cfg(unix)] to anyhow::anyhow import (only used in unix cfg block)
- Add #[cfg(not(windows))] to parse_file function (uses cat, only for cgroups)
- Remove unused std::io import, use std::io::Result directly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Windows compilation + convert integration tests to withTestBackend

- Fix unused import SYSTEM_ROOT in csharp_executor.rs on Windows by
  requiring both windows and csharp feature
- Fix unused variable id in handle_child.rs on Windows by adding
  #[allow(unused_variables)] since id is only used in cfg(unix) code
- Convert all RUN_INTEGRATION_TESTS dependent tests in sync_pull_push.test.ts
  to use withTestBackend pattern for automatic backend setup

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: configurable test features with CI_MINIMAL_FEATURES env var

- Default: full features (zip, private, enterprise) for local development
- CI mode: minimal features (zip only) when CI_MINIMAL_FEATURES=true
- Add shouldSkipOnCI() helper for tests requiring EE features
- Update EE-dependent tests to use shouldSkipOnCI()
- Add test instructions to cli/README.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: enable raw app tests (not EE-dependent)

Raw apps work with minimal features. 2 tests pass, 2 have test logic
bugs to investigate separately:
- "delete file and push" - file deletion not syncing correctly
- "dry-run push shows expected changes" - JSON output parsing issue

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: gate cgroups module to Linux only

cgroups are Linux-specific, the module was causing dead_code warnings
on Windows compilation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ci): add CI_MINIMAL_FEATURES env var to CLI tests workflow

Set CI_MINIMAL_FEATURES=true in both Linux and Windows test jobs so
the backend compiles with minimal features (zip only) and EE-dependent
tests self-skip via shouldSkipOnCI().

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): raw app tests and backend startup timing

- Add 5s delay after backend ready for migrations to complete
- Fix dry-run JSON output parsing (handle pretty-printed JSON)
- Temporarily ignore "delete file" test (needs isSuperset fix)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): raw app file deletion sync

- Add deepEqual check for files in raw_apps.ts isSuperset comparison
- Handle raw_app file deletions in sync.ts by re-pushing the entire app
- Fix test to remove CSS import before deleting the file

When deleting a file from a raw app, the sync now properly updates
the backend with the new file list (excluding the deleted file).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): Windows path separators in tests

Normalize paths for cross-platform comparison by converting
backslashes to forward slashes before path assertions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): normalize featurePaths in multi_instance_workspace test

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(cli): add mixed case paths sync tests for Windows compatibility

Add comprehensive tests for sync pull/push with capitalized folder paths
to catch Windows case-insensitivity issues:
- Scripts in f/MyFolder/MyScript
- Flows in f/MyFlows/DataProcessor
- Apps in f/MyApps/Dashboard
- Variables in f/MyVars/ApiKey
- Deeply nested paths with mixed case
- Multiple resources in same capitalized folder
- CamelCase folder names with numbers

Each test verifies the full pull -> modify -> push -> verify cycle.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(cli): add idempotency check to mixed case paths tests

After each push, pull again with --dry-run --json-output and verify
that no changes are detected. This ensures the sync is stable and
catches issues where pull/push cycles cause spurious diffs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 20:38:33 +00:00
Ruben Fiszel
c621a74804 fix: tighten operator permissions 2026-01-24 19:37:25 +00:00
Diego Imbert
05f5ef9cd9 (CI requires to be on main to be tested) use windmill flow for ephemeral backend action 2 (#7675)
* use windmill flow for ephemeral backend action

* fix

* nits

* nit
2026-01-24 19:34:51 +00:00
claude[bot]
05fa3cd013 feat: add workspace setting to disable error handler for u/ scripts/flows (#7634)
* feat: add workspace setting to disable error handler for u/ scripts/flows

Add a new workspace setting `error_handler_muted_on_user_path` that allows
disabling the error handler for jobs related to scripts/flows that start
with the "u/" prefix (user scripts/flows).

Changes:
- Add migration to add `error_handler_muted_on_user_path` column to workspace_settings
- Update WorkspaceSettings struct and get_settings query
- Update EditErrorHandler struct and edit_error_handler API endpoint
- Update error handler cache to include the new setting
- Add skip logic in send_error_to_workspace_handler for u/ paths
- Add toggle in workspace settings UI

The implementation uses the existing cached settings to avoid additional
database queries, making it efficient.

Closes #7633

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>

* all

* update ee private

* combine migrations

* sqlx

* fix: migration fixes for auto_invite JSONB column

- Fix TEXT[] to JSONB conversion using to_jsonb()
- Add GIN index on auto_invite for efficient ? operator queries
- Add index cleanup to down migration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* sqlx

* all

* all

* all

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 19:26:06 +00:00
Diego Imbert
e5e0830186 use windmill flow for ephemeral backend action (#7673) 2026-01-24 19:16:58 +00:00
Diego Imbert
8541cdba4c github action for /spawn-backend command (#7669) 2026-01-23 17:09:01 +00:00
Ruben Fiszel
8904f7b3f7 chore(main): release 1.614.0 (#7650)
* chore(main): release 1.614.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-01-23 12:56:16 +00:00
Ruben Fiszel
85e460d853 feat: add cache-rt command and SYNC_CACHED_RT env variable for resource types (#7666)
* feat: add cache-rt command and SYNC_CACHED_RT env variable for resource types

Add a new CLI command `cache-rt` that fetches resource types from the hub
and caches them locally. This command is run during Docker image build to
pre-populate the cache.

Add `SYNC_CACHED_RT` environment variable that, when set to true, syncs
cached resource types to the admins workspace's resource_type table on
server startup. The sync is incremental - it only updates resource types
that have changed.

Changes:
- Add HUB_RT_CACHE_DIR constant for resource type cache location
- Add cache-rt CLI command to fetch and cache resource types from hub
- Add sync_cached_resource_types() to sync cached types to database
- Update all Dockerfiles to run cache-rt during image build

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: parse schema string from hub into proper JSONB

The hub API returns schema as a JSON string that needs to be parsed
into a proper JSON value before inserting into the database.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 12:23:07 +00:00
Alexander Petric
08b483eaca fix: use pgoptions for iam rds connection (#7660)
* use pgoptions

* fix: use pgoptions for iam rds connection

* ee ref

* chore: update ee-repo-ref to 1549849fadc4e5634334a384bfe52343eb1e93f0

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

Previous ee-repo-ref: ffc1de1498a8018a9cbc2daba846e6c57d500a1c

New ee-repo-ref: 1549849fadc4e5634334a384bfe52343eb1e93f0

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-01-23 12:09:40 +00:00
Alexander Petric
e17a291c31 improve RHEL9 build (#7661)
* fix(ci): switch RHEL9 build from Depot to native arm64 buildx

* fix: sync frontend package-lock.json with package.json

* refactor(ci): use Depot multi-arch + crane for RHEL9 build

- Single multi-arch image (no -arm64/-amd64 suffixes)
- Use crane export to extract binaries directly from registry
- Avoids disk space issues by streaming instead of pulling full image
- Extracts both arm64 and amd64 binaries and libraries

* fix(ci): extract release/ directory to resolve hard links
2026-01-23 07:49:49 +00:00
Pyra
7249b82dba feat: better mixed versions handling (#7628) 2026-01-22 23:16:57 +00:00
wendrul
bb21486394 fix: Avoid logout when using deploy ui and no access to some deps (#7655) 2026-01-22 18:08:27 +00:00
centdix
0797e89aa0 feat(ai): handle google vertex for claude models + base url overrides (#7654)
* fix hardcoded gemini url

* allow overriding any provider url

* handle vertex

* same for chat proxy

* fix for chat
2026-01-22 17:28:51 +00:00
Diego Imbert
a384b4c23d Playwright E2E (#7520)
* clean plate

* npm i

* log in e2e

* global setup login

* set license key

* Revert "set license key"

This reverts commit 86d5db2c48.

* create datatable test

* fix wrong pg_creds

* data table + db manager e2e test

* DbManagerPage class

* small refactor

* create resource test + improvements

* text db manager in resources

* Factor test logic in classes

* refactoring

* refacto

* alter table test

* alter table e2e test

* set schema in test

* nits

* fix wrong schema var

* Correct setup and parallelization

* reducedMotion

* tests passing headless !

* bigger timeout

* start e2e docker compose

* e2e runs on all databases

* nit test uid fix

* refactp

* stash

* Better Workspace Storage settings

* minio setup

* nit

* nit

* super nit

* Permission settings in modal

* badge indicator

* Fetch alter table metadata much faster

* Upgrade duckdb to 1.4.3

* Ducklake tests

* Disable transactional DDL for Ducklake (bug on their side)

* git ignore env

* bigquery tests passes

* getJsonEnv

* load coldef in parallel

* Make Bigquery schema fetching much faster

* makeLoadTableMetaDataQuery for entire db in bigquery

* refactor getDbSchemas to avoid assignment side effect

* fix col def

* Better loading state mgmt

* snowflake

* fix snowflake primary keys

* Test CI

* fix setTimeout type

* remove type node

* test e2e ci

* Revert "test e2e ci"

This reverts commit bf98a755dc.

* remove ci

* fix snowflake pk query in alternate schemas

* nit wait for coldefs

* nit snowflake

* Snowflake fk fix

* UNPROCESSABLE_ENTITY instead of INTERNAL_ERROR

* nits

* fix alter pk in snowflake

* yet other fixes

* snowflake tests pass

* nits
2026-01-22 16:20:01 +00:00
Guilhem
7385726741 fix(frontend): Improve flow detail page (#7647)
* improve flow detail page

* Do not display seconds for last edit

* expand graph when possible

* nit

* make flowGraph min height reactive

* Add flow graph tab when chat mode enabled

* improve script detail layout

* nit

* nit

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* nit

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-01-22 15:55:18 +00:00
Diego Imbert
3b8a99e174 fix: add support for OIDC session tokens in S3 proxy headers (#7652)
* ee

* chore: update ee-repo-ref to dcc281b036fa4fcaa59c42ec3e93991e1eb8a536

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

Previous ee-repo-ref: 804789f22833b7b30ca06cfc98f9aa18714ee30f

New ee-repo-ref: dcc281b036fa4fcaa59c42ec3e93991e1eb8a536

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-01-22 15:28:48 +00:00
j-o-br
ac1a4b4495 add interpolated switch for resources (#7653) 2026-01-22 14:17:18 +00:00
Ruben Fiszel
161c114067 fix rhel9 image building 2026-01-22 11:14:20 +00:00
centdix
389499e576 feat(aichat): handle codestral from any provider (#7649)
* fix for codestral

* enable codestral

* fim with completion

* reduce context when using completion

* refactor: extract model detection utilities for Codestral/Mistral

Consolidate duplicated model detection logic into shared utilities
in copilot/utils.ts to improve maintainability and ensure consistency
across autocomplete support checks and Mistral-specific configurations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: add cursor marker to FIM-to-chat transformation prompt

Add explicit <CURSOR/> marker between prefix and suffix in the
FIM-to-chat transformation to help chat models better understand
where the completion should be inserted.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 19:54:30 +00:00
Guilhem
af14b09415 fix(frontend): improve ai chat ui (#7648)
* update chat to brand guidelines

* remove useless footer

* restore conversation count

* nit

* nit
2026-01-21 19:38:28 +00:00
Ruben Fiszel
22b222031e chore(main): release 1.613.4 (#7646)
* chore(main): release 1.613.4

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-01-21 14:23:09 +00:00
Ruben Fiszel
7848d361a5 fix: update git sync CLI to 1.613.2 2026-01-21 14:11:40 +00:00
Ruben Fiszel
ddfbe026c0 chore(main): release 1.613.3 (#7644)
* chore(main): release 1.613.3

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-01-21 13:23:00 +00:00
Ruben Fiszel
8cf456d74c fix(cli): normalize paths in wmill-lock for cross-platform compatibility (#7645)
Paths in wmill-lock.yaml are now normalized to use forward slashes,
ensuring the lockfile is portable between Windows and Linux. This also
applies to paths used in hash computation for flows and apps.

- Add normalizeLockPath() helper function
- Update v2LockPath() to normalize path and subpath
- Normalize paths in generateFlowHash() and generateAppHash()
- Add comprehensive tests for path normalization

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 13:18:35 +00:00
Ruben Fiszel
1e4fe01293 fix: update git sync CLI to 1.613.2 2026-01-21 13:06:47 +00:00
312 changed files with 18736 additions and 5733 deletions

View File

@@ -27,8 +27,6 @@ jobs:
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
- name: Docker meta
@@ -57,84 +55,62 @@ jobs:
run: |
cp ./docker/RHEL9/Dockerfile ./Dockerfile
- name: Build and push publicly ee amd64
- name: Build and push EE (multi-arch)
uses: depot/build-push-action@v1
with:
context: .
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp,private
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,native_trigger,static_frontend,all_languages,deno_core,mcp,private
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
tags: |
${{ steps.meta-ee-public.outputs.tags }}-amd64
${{ steps.meta-ee-public.outputs.tags }}
labels: |
${{ steps.meta-ee-public.outputs.labels }}-amd64
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
- name: Build and push publicly ee arm64
uses: depot/build-push-action@v1
with:
context: .
platforms: linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp,private
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
tags: |
${{ steps.meta-ee-public.outputs.tags }}-arm64
labels: |
${{ steps.meta-ee-public.outputs.labels }}-arm64
org.opencontainers.image.licenses=Windmill-Enterprise-License
- name: Install crane
uses: imjasonh/setup-crane@v0.4
- uses: shrink/actions-docker-extract@v3
id: extract-ee-amd64
with:
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
path: "/windmill/target/release/windmill"
- uses: shrink/actions-docker-extract@v3
id: extract-duckdb-ffi-internal
with:
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
path: "/usr/src/app/libwindmill_duckdb_ffi_internal.so"
# - uses: shrink/actions-docker-extract@v3
# id: extract-ee-arm64
# with:
# image: ${{ steps.meta-ee-public.outputs.tags}}-arm64
# path: "/windmill/target/release/windmill"
- name: Rename binary with corresponding architecture
- name: Extract binaries with crane
run: |
mv "${{ steps.extract-ee-amd64.outputs.destination }}/windmill" "${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9"
# mv "${{ steps.extract-ee-arm64.outputs.destination }}/windmill" "${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9"
mkdir -p extracted
# Extract arm64 binary (include deps/ for hard link resolution)
mkdir -p /tmp/arm64
crane export --platform linux/arm64 ${{ steps.meta-ee-public.outputs.tags }} - \
| tar -xf - -C /tmp/arm64 windmill/target/release/ usr/src/app/libwindmill_duckdb_ffi_internal.so
cp /tmp/arm64/windmill/target/release/windmill extracted/windmill-ee-arm64-rhel9
cp /tmp/arm64/usr/src/app/libwindmill_duckdb_ffi_internal.so extracted/libwindmill_duckdb_ffi_internal-arm64.so
rm -rf /tmp/arm64
# Extract amd64 binary
mkdir -p /tmp/amd64
crane export --platform linux/amd64 ${{ steps.meta-ee-public.outputs.tags }} - \
| tar -xf - -C /tmp/amd64 windmill/target/release/ usr/src/app/libwindmill_duckdb_ffi_internal.so
cp /tmp/amd64/windmill/target/release/windmill extracted/windmill-ee-amd64-rhel9
cp /tmp/amd64/usr/src/app/libwindmill_duckdb_ffi_internal.so extracted/libwindmill_duckdb_ffi_internal-amd64.so
rm -rf /tmp/amd64
- uses: actions/upload-artifact@v4
with:
name: RHEL9-arm64 build
path: extracted/windmill-ee-arm64-rhel9
- uses: actions/upload-artifact@v4
with:
name: RHEL9-amd64 build
path: ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9
path: extracted/windmill-ee-amd64-rhel9
- uses: actions/upload-artifact@v4
with:
name: RHEL9-arm64 dynamic libraries build
path: extracted/libwindmill_duckdb_ffi_internal-arm64.so
- uses: actions/upload-artifact@v4
with:
name: RHEL9-amd64 dynamic libraries build
path: ${{ steps.extract-duckdb-ffi-internal.outputs.destination }}/libwindmill_duckdb_ffi_internal.so
# - uses: actions/upload-artifact@v4
# with:
# name: RHEL9-arm64 build
# path:
# ${{ steps.extract-ee-arm64.outputs.destination
# }}/windmill-ee-arm64-rhel9
# - name: Attach binary to release
# uses: softprops/action-gh-release@v2
# if: startsWith(github.ref, 'refs/tags/')
# with:
# files: |
# ${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9
# ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9
path: extracted/libwindmill_duckdb_ffi_internal-amd64.so

View File

@@ -64,7 +64,7 @@ jobs:
platforms: linux/amd64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp,private
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,native_trigger,static_frontend,all_languages,deno_core,mcp,private
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
@@ -81,7 +81,7 @@ jobs:
platforms: linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp,private
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,native_trigger,static_frontend,all_languages,deno_core,mcp,private
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}

View File

@@ -57,7 +57,7 @@ jobs:
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
mkdir frontend/build && cd backend
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages_windows,mcp,private
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,native_trigger,static_frontend,all_languages_windows,mcp,bedrock,private
- name: Rename binary with corresponding architecture
run: |
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"

161
.github/workflows/cli-tests.yml vendored Normal file
View File

@@ -0,0 +1,161 @@
name: CLI Tests
on:
push:
branches: [main]
paths:
- 'cli/**'
- '.github/workflows/cli-tests.yml'
pull_request:
branches: [main]
paths:
- 'cli/**'
- '.github/workflows/cli-tests.yml'
env:
CARGO_TERM_COLOR: always
SQLX_OFFLINE: true
jobs:
build-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Generate Windmill client
working-directory: cli
run: ./gen_wm_client.sh
- name: Run CLI build
working-directory: cli
run: ./build.sh
test-linux:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: changeme
POSTGRES_DB: windmill
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: true
cache-workspaces: backend
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Generate Windmill clients
working-directory: cli
run: |
./gen_wm_client.sh
./windmill-utils-internal/gen_wm_client.sh
- name: Run CLI tests
working-directory: cli
env:
DATABASE_URL: postgres://postgres:changeme@localhost:5432
CI_MINIMAL_FEATURES: "true"
run: |
deno test --no-check --allow-all test/ \
--ignore=test/cargo_backend_example.test.ts
test-windows:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PostgreSQL
uses: ikalnytskyi/action-setup-postgres@v6
with:
username: postgres
password: changeme
database: windmill
port: 5432
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: true
cache-workspaces: backend
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Generate Windmill clients
working-directory: cli
shell: bash
run: |
./gen_wm_client.sh
./windmill-utils-internal/gen_wm_client.sh
- name: Run CLI tests
working-directory: cli
shell: pwsh
env:
DATABASE_URL: postgres://postgres:changeme@localhost:5432
CI_MINIMAL_FEATURES: "true"
run: |
deno test --no-check --allow-all test/ `
--ignore=test/cargo_backend_example.test.ts
# Combined summary job for branch protection
test-summary:
runs-on: ubuntu-latest
needs: [build-check, test-linux, test-windows]
if: always()
steps:
- name: Check test results
run: |
if [ "${{ needs.build-check.result }}" != "success" ]; then
echo "Build check failed"
exit 1
fi
if [ "${{ needs.test-linux.result }}" != "success" ] || [ "${{ needs.test-windows.result }}" != "success" ]; then
echo "Some tests failed"
exit 1
fi
echo "All checks passed"

View File

@@ -97,7 +97,7 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
build-args: |
features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages,deno_core,mcp,private
features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages,deno_core,mcp,bedrock,private
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
${{ steps.meta-public.outputs.tags }}
@@ -159,7 +159,7 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages,private,deno_core,mcp
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,native_trigger,static_frontend,all_languages,private,deno_core,mcp,bedrock
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
${{ steps.meta-ee-public.outputs.tags }}
@@ -167,39 +167,6 @@ jobs:
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
# disabled until we make it 100% reliable and add more meaningful tests
# playwright:
# runs-on: [self-hosted, new]
# needs: [build]
# services:
# postgres:
# image: postgres
# env:
# POSTGRES_DB: windmill
# POSTGRES_USER: admin
# POSTGRES_PASSWORD: changeme
# ports:
# - 5432:5432
# options: >-
# --health-cmd pg_isready
# --health-interval 10s
# --health-timeout 5s
# --health-retries 5
# steps:
# - uses: actions/checkout@v4
# - name: "Docker"
# run: echo "::set-output name=id::$(docker run --network=host --rm -d -p 8000:8000 --privileged -it -e DATABASE_URL=postgres://admin:changeme@localhost:5432/windmill -e BASE_INTERNAL_URL=http://localhost:8000 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest)"
# id: docker-container
# - uses: actions/setup-node@v3
# with:
# node-version: 16
# - name: "Playwright run"
# timeout-minutes: 2
# run: cd frontend && npm ci @playwright/test && npx playwright install && export BASE_URL=http://localhost:8000 && npm run test
# - name: "Clean up"
# run: docker kill ${{ steps.docker-container.outputs.id }}
# if: always()
attach_amd64_binary_to_release:
needs: [build, build_ee]
runs-on: ubicloud

View File

@@ -59,7 +59,7 @@ jobs:
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
mkdir frontend/build && cd backend
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages_windows,mcp,private
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,native_trigger,static_frontend,all_languages_windows,mcp,bedrock,private
- name: Rename binary with corresponding architecture
run: |
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"

View File

@@ -0,0 +1,75 @@
name: Spawn Ephemeral Backend
on:
issue_comment:
types: [created]
workflow_dispatch:
inputs:
pr_number:
description: "PR number"
required: true
type: number
jobs:
spawn-backend:
# Only run on PR comments that contain /spawn-backend, or manual dispatch
if: |
github.event_name == 'workflow_dispatch' ||
(github.event.issue.pull_request && contains(github.event.comment.body, '/spawn-backend'))
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- name: Get PR details
id: pr-details
uses: actions/github-script@v7
with:
script: |
const prNumber = context.eventName === 'workflow_dispatch'
? context.payload.inputs.pr_number
: context.issue.number;
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
core.setOutput('commit_hash', pr.data.head.sha);
core.setOutput('pr_number', context.issue.number);
- name: Trigger Windmill flow
id: trigger-flow
run: |
RESPONSE=$(curl -s -X POST "https://app.windmill.dev/api/w/windmill-labs/jobs/run/f/f/all/run_ephemeral_backend" \
-H "Authorization: Bearer ${{ secrets.WINDMILL_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{
"manager_url": "${{ secrets.EPHEMERAL_BACKEND_QUEUE_URL }}",
"commit_hash": "${{ steps.pr-details.outputs.commit_hash }}",
"pr_number": ${{ steps.pr-details.outputs.pr_number }}
}')
JOB_UUID=$(echo "$RESPONSE" | jq -r '.id // empty')
if [ -z "$JOB_UUID" ]; then
echo "Failed to get job UUID from response: $RESPONSE"
exit 1
fi
echo "job_uuid=$JOB_UUID" >> $GITHUB_OUTPUT
- name: Post comment with job link
uses: actions/github-script@v7
with:
script: |
const jobUuid = '${{ steps.trigger-flow.outputs.job_uuid }}';
const jobUrl = `https://app.windmill.dev/run/${jobUuid}?workspace=windmill-labs`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `🚀 Ephemeral backend spawning started!\n\nView job progress: ${jobUrl}`
});

View File

@@ -1,5 +1,79 @@
# Changelog
## [1.615.3](https://github.com/windmill-labs/windmill/compare/v1.615.2...v1.615.3) (2026-01-26)
### Bug Fixes
* change min worker version to 1.420.0 ([95e5d7e](https://github.com/windmill-labs/windmill/commit/95e5d7e469bcce827fef55a0f6e176ebb110ffc1))
## [1.615.2](https://github.com/windmill-labs/windmill/compare/v1.615.1...v1.615.2) (2026-01-26)
### Bug Fixes
* add SSL_CERT_FILE to python install ([5e56d75](https://github.com/windmill-labs/windmill/commit/5e56d751f3085b64e05d6a7ef0b23838efe408a4))
* mixed version error ([#7686](https://github.com/windmill-labs/windmill/issues/7686)) ([1ae157d](https://github.com/windmill-labs/windmill/commit/1ae157dadd17a7d759ea927976bbabaa47ac328d))
* set 3.12 as python fallback if no version explicitely set ([f880655](https://github.com/windmill-labs/windmill/commit/f880655e32793ce50fec5a63040d041c29b7d2dc))
## [1.615.1](https://github.com/windmill-labs/windmill/compare/v1.615.0...v1.615.1) (2026-01-26)
### Bug Fixes
* **aiagent:** fix usage for gemini 3 models ([#7682](https://github.com/windmill-labs/windmill/issues/7682)) ([29b274a](https://github.com/windmill-labs/windmill/commit/29b274a08a85d50ead1f1b71949b2c261b6728be))
## [1.615.0](https://github.com/windmill-labs/windmill/compare/v1.614.0...v1.615.0) (2026-01-26)
### Features
* add workspace setting to disable error handler for u/ scripts/flows ([#7634](https://github.com/windmill-labs/windmill/issues/7634)) ([05fa3cd](https://github.com/windmill-labs/windmill/commit/05fa3cd0130220de924b495296c2aac5c4520ac7))
* **ai:** native bedrock compatibility ([#7668](https://github.com/windmill-labs/windmill/issues/7668)) ([2553d98](https://github.com/windmill-labs/windmill/commit/2553d987d9c08987bf10fe2ef7c91d778aed04fc))
### Bug Fixes
* allow SERVER_BIND_ADDR to override worker bind address ([522fa98](https://github.com/windmill-labs/windmill/commit/522fa98d7194093ebb2cfe2eefea870f610d4216))
* make DateInput reactive to external value changes and handle empty dateFormat ([22ea612](https://github.com/windmill-labs/windmill/commit/22ea61207ae4c7bad38eb4e0a85eeadfb9e9137b))
* persist "Planned later" and "Schedule" toggles in localStorage on runs page ([35081ca](https://github.com/windmill-labs/windmill/commit/35081ca9d2cc506b9068fed5eb28ef9f7d650b24))
* tighten operator permissions ([c621a74](https://github.com/windmill-labs/windmill/commit/c621a74804f4f6e8318819c01e3a23a17698588b))
* update rmcp type aliases to non-deprecated versions ([bb9adca](https://github.com/windmill-labs/windmill/commit/bb9adca38f8694e21a8cea27ba13e029accc3e57))
## [1.614.0](https://github.com/windmill-labs/windmill/compare/v1.613.4...v1.614.0) (2026-01-23)
### Features
* add cache-rt command and SYNC_CACHED_RT env variable for resource types ([#7666](https://github.com/windmill-labs/windmill/issues/7666)) ([85e460d](https://github.com/windmill-labs/windmill/commit/85e460d853cbd9f8d245efb9009690c0bb468bfc))
* **aichat:** handle codestral from any provider ([#7649](https://github.com/windmill-labs/windmill/issues/7649)) ([389499e](https://github.com/windmill-labs/windmill/commit/389499e57696dc4805080a9e6b737b1aef4566be))
* **ai:** handle google vertex for claude models + base url overrides ([#7654](https://github.com/windmill-labs/windmill/issues/7654)) ([0797e89](https://github.com/windmill-labs/windmill/commit/0797e89aa00e57b4e162df32d7b0a041ad6db71e))
* better mixed versions handling ([#7628](https://github.com/windmill-labs/windmill/issues/7628)) ([7249b82](https://github.com/windmill-labs/windmill/commit/7249b82dbaee2d14cb5768233c2026a6ab44231f))
### Bug Fixes
* add support for OIDC session tokens in S3 proxy headers ([#7652](https://github.com/windmill-labs/windmill/issues/7652)) ([3b8a99e](https://github.com/windmill-labs/windmill/commit/3b8a99e174682ad90a9a0d3957902e09c9e0a195))
* Avoid logout when using deploy ui and no access to some deps ([#7655](https://github.com/windmill-labs/windmill/issues/7655)) ([bb21486](https://github.com/windmill-labs/windmill/commit/bb2148639441b86c6c966119df4711066fc94c85))
* **frontend:** improve ai chat ui ([#7648](https://github.com/windmill-labs/windmill/issues/7648)) ([af14b09](https://github.com/windmill-labs/windmill/commit/af14b0941581eec98061d4cbae159a061f1d5eee))
* **frontend:** Improve flow detail page ([#7647](https://github.com/windmill-labs/windmill/issues/7647)) ([7385726](https://github.com/windmill-labs/windmill/commit/738572674123a00a5e37a0c875b2649608c70f0a))
* use pgoptions for iam rds connection ([#7660](https://github.com/windmill-labs/windmill/issues/7660)) ([08b483e](https://github.com/windmill-labs/windmill/commit/08b483eacafcd161537b9a09f63640eeacad087f))
## [1.613.4](https://github.com/windmill-labs/windmill/compare/v1.613.3...v1.613.4) (2026-01-21)
### Bug Fixes
* update git sync CLI to 1.613.2 ([7848d36](https://github.com/windmill-labs/windmill/commit/7848d361a546ef8a2ef9fa20a0399f2e8473f685))
## [1.613.3](https://github.com/windmill-labs/windmill/compare/v1.613.2...v1.613.3) (2026-01-21)
### Bug Fixes
* **cli:** normalize paths in wmill-lock for cross-platform compatibility ([#7645](https://github.com/windmill-labs/windmill/issues/7645)) ([8cf456d](https://github.com/windmill-labs/windmill/commit/8cf456d74c79921806edbcd0c9fde462f7202188))
* update git sync CLI to 1.613.2 ([1e4fe01](https://github.com/windmill-labs/windmill/commit/1e4fe01293e65ac130b368fbef45a1571ee2b6d7))
## [1.613.2](https://github.com/windmill-labs/windmill/compare/v1.613.1...v1.613.2) (2026-01-21)

View File

@@ -254,7 +254,7 @@ COPY ./frontend/src/lib/hubPaths.json ${APP}/hubPaths.json
RUN windmill cache ${APP}/hubPaths.json && rm ${APP}/hubPaths.json
RUN windmill cache-rt
# Create a non-root user 'windmill' with UID and GID 1000
RUN addgroup --gid 1000 windmill && \

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO app_version (id, app_id, value, created_by, created_at)\n VALUES (3001, 3001, '{\"grid\": []}', 'admin', NOW())",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "01c040b04b487e86b7f4ff38b0faacf6af2c284ae446860113c82bc4e1da08ab"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET auto_invite = COALESCE(auto_invite, '{}'::jsonb)\n || jsonb_build_object('instance_groups', $2::jsonb, 'instance_groups_roles', $3::jsonb)\n WHERE workspace_id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Jsonb",
"Jsonb"
]
},
"nullable": []
},
"hash": "03caaec9f41be87eac32e163d7a829e58ae993932e9bbad5aebab4770cc44d61"
}

View File

@@ -46,11 +46,11 @@
]
},
"nullable": [
false,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
true
]

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT success_handler_extra_args FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "success_handler_extra_args",
"type_info": "Json"
}
],
"parameters": {
"Left": []
},
"nullable": [
true
]
},
"hash": "085bbcfcebc9e56984295046c48722f3510548eaf525c499ad0e24cdf8332b22"
}

View File

@@ -29,7 +29,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -30,163 +30,128 @@
},
{
"ordinal": 5,
"name": "auto_invite_domain",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "auto_invite_operator",
"type_info": "Bool"
},
{
"ordinal": 7,
"name": "customer_id",
"type_info": "Varchar"
},
{
"ordinal": 8,
"ordinal": 6,
"name": "plan",
"type_info": "Varchar"
},
{
"ordinal": 9,
"ordinal": 7,
"name": "webhook",
"type_info": "Text"
},
{
"ordinal": 10,
"ordinal": 8,
"name": "deploy_to",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "error_handler",
"type_info": "Varchar"
},
{
"ordinal": 12,
"ordinal": 9,
"name": "ai_config",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "error_handler_extra_args",
"type_info": "Json"
},
{
"ordinal": 14,
"name": "error_handler_muted_on_cancel",
"type_info": "Bool"
},
{
"ordinal": 15,
"ordinal": 10,
"name": "large_file_storage",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"ordinal": 11,
"name": "git_sync",
"type_info": "Jsonb"
},
{
"ordinal": 17,
"ordinal": 12,
"name": "default_app",
"type_info": "Varchar"
},
{
"ordinal": 18,
"name": "auto_add",
"type_info": "Bool"
},
{
"ordinal": 19,
"ordinal": 13,
"name": "default_scripts",
"type_info": "Jsonb"
},
{
"ordinal": 20,
"ordinal": 14,
"name": "deploy_ui",
"type_info": "Jsonb"
},
{
"ordinal": 21,
"ordinal": 15,
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 22,
"ordinal": 16,
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 23,
"ordinal": 17,
"name": "operator_settings",
"type_info": "Jsonb"
},
{
"ordinal": 24,
"ordinal": 18,
"name": "teams_command_script",
"type_info": "Text"
},
{
"ordinal": 25,
"ordinal": 19,
"name": "teams_team_id",
"type_info": "Text"
},
{
"ordinal": 26,
"ordinal": 20,
"name": "teams_team_name",
"type_info": "Text"
},
{
"ordinal": 27,
"ordinal": 21,
"name": "git_app_installations",
"type_info": "Jsonb"
},
{
"ordinal": 28,
"ordinal": 22,
"name": "ducklake",
"type_info": "Jsonb"
},
{
"ordinal": 29,
"name": "auto_add_instance_groups",
"type_info": "TextArray"
},
{
"ordinal": 30,
"name": "auto_add_instance_groups_roles",
"type_info": "Jsonb"
},
{
"ordinal": 31,
"ordinal": 23,
"name": "slack_oauth_client_id",
"type_info": "Varchar"
},
{
"ordinal": 32,
"ordinal": 24,
"name": "slack_oauth_client_secret",
"type_info": "Varchar"
},
{
"ordinal": 33,
"ordinal": 25,
"name": "datatable",
"type_info": "Jsonb"
},
{
"ordinal": 34,
"ordinal": 26,
"name": "teams_team_guid",
"type_info": "Text"
},
{
"ordinal": 35,
"name": "success_handler",
"type_info": "Text"
"ordinal": 27,
"name": "auto_invite",
"type_info": "Jsonb"
},
{
"ordinal": 36,
"name": "success_handler_extra_args",
"type_info": "Json"
"ordinal": 28,
"name": "error_handler",
"type_info": "Jsonb"
},
{
"ordinal": 29,
"name": "success_handler",
"type_info": "Jsonb"
}
],
"parameters": {
@@ -209,12 +174,6 @@
true,
true,
true,
false,
true,
true,
true,
true,
true,
true,
true,
true,
@@ -230,7 +189,6 @@
true,
true,
true,
true,
true
]
},

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET auto_invite = COALESCE(auto_invite, '{}'::jsonb) - 'instance_groups' - 'instance_groups_roles'\n WHERE workspace_id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "0984e469bbd5f97cf9a6cac4bf5700bb6b1a99f6abfb3390a54a8a42c6768903"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET auto_invite_domain = NULL, auto_invite_operator = NULL, auto_add = NULL WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "0c9ad812013ff476a79ca8d6bb8b7a73d9492e07680732af9af09e223ade1f37"
}

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT success_handler FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "success_handler",
"type_info": "Text"
}
],
"parameters": {
"Left": []
},
"nullable": [
true
]
},
"hash": "10a40902f5aba38aea23f2b0776b54752362c9cc7deb179f75c7f1795866d13a"
}

View File

@@ -121,7 +121,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COALESCE(auto_add_instance_groups, '{}') FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "coalesce",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "18e550f4ec23d465632449b88c4b25931f145f771b93828e8e6dfcc1f906443d"
}

View File

@@ -39,7 +39,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE app SET versions = ARRAY[3001::bigint] WHERE id = 3001",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "1ad384eeb3946ef7c492124c69fbc47caebc25215a430d6b301b35e265888159"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, edited_at, schema, extra_perms)\n VALUES ('test-workspace', 'u/operator/existing_flow', 'Existing flow', '', '{\"modules\": []}', 'admin', NOW(), '{}', '{}')",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "1fa27bd47ab66b3f301ca43ef93fb7cf5f2b76f013c274245af13d7d727ebf1f"
}

View File

@@ -39,7 +39,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET auto_invite = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb",
"Text"
]
},
"nullable": []
},
"hash": "255ba68caa78d0e814ea817693a319f769907025f9c7d1150d45e8ecb1bff4ab"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM workspace_settings WHERE workspace_id = $1",
"query": "\n SELECT\n workspace_id,\n slack_team_id,\n teams_team_id,\n teams_team_name,\n teams_team_guid,\n slack_name,\n slack_command_script,\n teams_command_script,\n slack_email,\n slack_oauth_client_id,\n slack_oauth_client_secret,\n customer_id,\n plan,\n webhook,\n deploy_to,\n ai_config,\n large_file_storage,\n datatable,\n ducklake,\n git_sync,\n deploy_ui,\n default_app,\n default_scripts,\n mute_critical_alerts,\n color,\n operator_settings,\n git_app_installations,\n auto_invite,\n error_handler,\n success_handler\n FROM\n workspace_settings\n WHERE\n workspace_id = $1\n ",
"describe": {
"columns": [
{
@@ -15,92 +15,92 @@
},
{
"ordinal": 2,
"name": "teams_team_id",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "teams_team_name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "teams_team_guid",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "slack_name",
"type_info": "Varchar"
},
{
"ordinal": 3,
"ordinal": 6,
"name": "slack_command_script",
"type_info": "Varchar"
},
{
"ordinal": 4,
"ordinal": 7,
"name": "teams_command_script",
"type_info": "Text"
},
{
"ordinal": 8,
"name": "slack_email",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "auto_invite_domain",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "auto_invite_operator",
"type_info": "Bool"
},
{
"ordinal": 7,
"name": "customer_id",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "plan",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "webhook",
"type_info": "Text"
"name": "slack_oauth_client_id",
"type_info": "Varchar"
},
{
"ordinal": 10,
"name": "deploy_to",
"name": "slack_oauth_client_secret",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "error_handler",
"name": "customer_id",
"type_info": "Varchar"
},
{
"ordinal": 12,
"name": "plan",
"type_info": "Varchar"
},
{
"ordinal": 13,
"name": "webhook",
"type_info": "Text"
},
{
"ordinal": 14,
"name": "deploy_to",
"type_info": "Varchar"
},
{
"ordinal": 15,
"name": "ai_config",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "error_handler_extra_args",
"type_info": "Json"
},
{
"ordinal": 14,
"name": "error_handler_muted_on_cancel",
"type_info": "Bool"
},
{
"ordinal": 15,
"ordinal": 16,
"name": "large_file_storage",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"name": "git_sync",
"ordinal": 17,
"name": "datatable",
"type_info": "Jsonb"
},
{
"ordinal": 17,
"name": "default_app",
"type_info": "Varchar"
},
{
"ordinal": 18,
"name": "auto_add",
"type_info": "Bool"
"name": "ducklake",
"type_info": "Jsonb"
},
{
"ordinal": 19,
"name": "default_scripts",
"name": "git_sync",
"type_info": "Jsonb"
},
{
@@ -110,83 +110,48 @@
},
{
"ordinal": 21,
"name": "default_app",
"type_info": "Varchar"
},
{
"ordinal": 22,
"name": "default_scripts",
"type_info": "Jsonb"
},
{
"ordinal": 23,
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 22,
"ordinal": 24,
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 23,
"ordinal": 25,
"name": "operator_settings",
"type_info": "Jsonb"
},
{
"ordinal": 24,
"name": "teams_command_script",
"type_info": "Text"
},
{
"ordinal": 25,
"name": "teams_team_id",
"type_info": "Text"
},
{
"ordinal": 26,
"name": "teams_team_name",
"type_info": "Text"
},
{
"ordinal": 27,
"name": "git_app_installations",
"type_info": "Jsonb"
},
{
"ordinal": 27,
"name": "auto_invite",
"type_info": "Jsonb"
},
{
"ordinal": 28,
"name": "ducklake",
"name": "error_handler",
"type_info": "Jsonb"
},
{
"ordinal": 29,
"name": "auto_add_instance_groups",
"type_info": "TextArray"
},
{
"ordinal": 30,
"name": "auto_add_instance_groups_roles",
"type_info": "Jsonb"
},
{
"ordinal": 31,
"name": "slack_oauth_client_id",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "slack_oauth_client_secret",
"type_info": "Varchar"
},
{
"ordinal": 33,
"name": "datatable",
"type_info": "Jsonb"
},
{
"ordinal": 34,
"name": "teams_team_guid",
"type_info": "Text"
},
{
"ordinal": 35,
"name": "success_handler",
"type_info": "Text"
},
{
"ordinal": 36,
"name": "success_handler_extra_args",
"type_info": "Json"
"type_info": "Jsonb"
}
],
"parameters": {
@@ -199,6 +164,10 @@
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
@@ -209,11 +178,6 @@
true,
true,
true,
false,
true,
true,
true,
true,
true,
true,
true,
@@ -225,14 +189,8 @@
false,
true,
true,
true,
true,
true,
true,
true,
true,
true
]
},
"hash": "1730f39fd1793d45fbb41b21389c61296a3ff7489ae12f52a19f9543173ac597"
"hash": "289919809e16aee33c81951b05a4795de710421bcd3e4c06588e56092677bd05"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = '{\"path\": \"script/f/test/success_handler\", \"extra_args\": {\"key\": \"value\"}}'::jsonb\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "28f3dfb70aed943ad3d64da608168c027c645afb73dfc2360245b68ba593cab4"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET auto_add_instance_groups = NULL, auto_add_instance_groups_roles = NULL WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "31db242523c534b2abbb5f4985f56dd4493d19611ed988d694d9f4289dc29c48"
}

View File

@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT error_handler->>'path' FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "397f5bef6454770910189db812ad549d50af537c43b4b6ded63b6e83070243be"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET auto_add_instance_groups = $2, auto_add_instance_groups_roles = $3 WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"TextArray",
"Jsonb"
]
},
"nullable": []
},
"hash": "404233e74aaafd987879c6c87d1fd80928e6fade09e60a9a2d35121c81885cca"
}

View File

@@ -23,7 +23,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n workspace_settings\n SET\n success_handler = NULL,\n success_handler_extra_args = NULL\n WHERE\n workspace_id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "4977b4027861ca234e95559a8b550bc8849f7ed60a471d46f3be3d39664a48ca"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET\n auto_add_instance_groups = array_remove(auto_add_instance_groups, $1),\n auto_add_instance_groups_roles = auto_add_instance_groups_roles - $1\n WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "4a446b97cf813226d25ca40cefca2999cdcf938f817327e9168b3edb0fce7fb7"
}

View File

@@ -31,7 +31,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}
@@ -68,7 +69,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n workspace_settings\n SET\n error_handler = NULL,\n error_handler_extra_args = NULL,\n error_handler_muted_on_cancel = false\n WHERE\n workspace_id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "5ad2c883d26f39f3c141806428a329951ef19a1cb3e1b429fcd1abe0e2db45b5"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO app (id, workspace_id, path, summary, versions, policy, extra_perms)\n VALUES (3001, 'test-workspace', 'u/operator/existing_app', 'Existing app', '{}',\n '{\"on_behalf_of\": \"u/admin\", \"on_behalf_of_email\": \"admin@windmill.dev\", \"execution_mode\": \"viewer\"}', '{}')",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "5b140cb478aa32ac38fb831d6af960ffc33da5f31bf780e8fd6a66d5150b8027"
}

View File

@@ -244,7 +244,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,35 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id,\n (auto_invite->>'operator')::boolean as \"is_operator: bool\",\n (auto_invite->>'mode') = 'add' as \"is_auto_add: bool\"\n FROM workspace_settings ws\n WHERE (auto_invite->>'domain' = $1 OR auto_invite->>'domain' = '*')\n AND (auto_invite->>'enabled')::boolean = true\n AND NOT EXISTS (SELECT 1 FROM usr WHERE workspace_id = ws.workspace_id AND email = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "is_operator: bool",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "is_auto_add: bool",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false,
null,
null
]
},
"hash": "5dafddc81419883beda4cc9acb3679b3d7c97f6c137b189d552182899782e99f"
}

View File

@@ -30,7 +30,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET success_handler = NULL WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "63ad0e3cca16987dba0be7b3efb522c6e652cfa86f10642ade6aaadd6174fb52"
}

View File

@@ -1,17 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET auto_invite_domain = $1, auto_invite_operator = $2, auto_add = $4 WHERE workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Bool",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "64c5ca0bd4a2c42d6f5415fae1de21295673c45e4caae1bdbb47517d4608dc8d"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = '{\"path\": \"script/f/test/success_handler\"}'::jsonb\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "65016ea993fb40d4ab6b0a6f15c2082e8dfbaada01243bae07065c089bc42fa9"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO usr_to_group (workspace_id, group_, usr) VALUES ('test-workspace', 'editors', 'charlie')",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "6c24b5c08341979e02b7968242369c87a9d29370ec985d2c8c28633cd078ffaf"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = 'script/f/test/success_handler',\n success_handler_extra_args = '{\"key\": \"value\"}'::json\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "6eaa0af9c5e0a8d64c3202753c9c3cef39361b0987a22b7d2b2346652f81177e"
}

View File

@@ -39,7 +39,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT auto_invite->'instance_groups' FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "75e740531bf794a8568350348253612cfbdecb9fb9cf768f431d4dbd4cd56cfb"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n workspace_id,\n auto_add_instance_groups_roles\n FROM workspace_settings\n WHERE\n auto_add_instance_groups IS NOT NULL\n AND $1 = ANY(auto_add_instance_groups)\n ",
"query": "\n SELECT\n workspace_id,\n auto_invite->'instance_groups_roles' as instance_groups_roles\n FROM workspace_settings\n WHERE\n auto_invite->'instance_groups' IS NOT NULL\n AND auto_invite->'instance_groups' ? $1\n ",
"describe": {
"columns": [
{
@@ -10,7 +10,7 @@
},
{
"ordinal": 1,
"name": "auto_add_instance_groups_roles",
"name": "instance_groups_roles",
"type_info": "Jsonb"
}
],
@@ -21,8 +21,8 @@
},
"nullable": [
false,
true
null
]
},
"hash": "3ebc91867be0a4830ef4dbbe833aed348f78e3cb68fb1f3c855a491bdcda5017"
"hash": "7e01ef5799168c0fc2779d42ce352827e2fda6711c0a1b104ca6435ddb14b47d"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n eig.igroup as group_name,\n ws.auto_add_instance_groups_roles\n FROM email_to_igroup eig\n INNER JOIN workspace_settings ws ON ws.workspace_id = $1\n WHERE eig.email = $2\n AND eig.igroup = ANY(ws.auto_add_instance_groups)\n ",
"query": "\n SELECT\n eig.igroup as group_name,\n ws.auto_invite->'instance_groups_roles' as instance_groups_roles\n FROM email_to_igroup eig\n INNER JOIN workspace_settings ws ON ws.workspace_id = $1\n WHERE eig.email = $2\n AND ws.auto_invite->'instance_groups' ? eig.igroup\n ",
"describe": {
"columns": [
{
@@ -10,7 +10,7 @@
},
{
"ordinal": 1,
"name": "auto_add_instance_groups_roles",
"name": "instance_groups_roles",
"type_info": "Jsonb"
}
],
@@ -22,8 +22,8 @@
},
"nullable": [
false,
true
null
]
},
"hash": "1ff185d8b8b897a72180cd0002e0f7e9858eef249577ce23969522793c6b5608"
"hash": "7e5913aa98624836a9bd7b5cc5cb10cc79a1249f48de45ea1c15235d4b05576b"
}

View File

@@ -26,7 +26,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n error_handler->>'path'\n FROM\n workspace_settings\n WHERE\n workspace_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "825ee06c5f88436ff7bb45e389552836ae8496d75d7cf7fee497b14943b1b6f6"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO token (token, email, label, super_admin, owner, workspace_id)\n VALUES ('CHARLIE_TOKEN_NEW', 'charlie@windmill.dev', 'Charlie new token', false, 'u/charlie', 'test-workspace')",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "8515537f73c132e62c4dafad1e8d8e56f0c70dccd0edbc9667f550b31ab54c18"
}

View File

@@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "SELECT success_handler->'extra_args' FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "87044e1466cd114cbef336620e96dc29f3f930149fedc240d44c614dfc794ff7"
}

View File

@@ -34,7 +34,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n ig.name as group_name,\n ws.workspace_id,\n w.name as workspace_name,\n ws.auto_add_instance_groups_roles->ig.name as role\n FROM instance_group ig\n INNER JOIN workspace_settings ws ON ws.auto_add_instance_groups IS NOT NULL\n AND ig.name = ANY(ws.auto_add_instance_groups)\n INNER JOIN workspace w ON w.id = ws.workspace_id AND w.deleted = false\n ORDER BY ig.name, ws.workspace_id\n ",
"query": "\n SELECT\n ig.name as group_name,\n ws.workspace_id,\n w.name as workspace_name,\n ws.auto_invite->'instance_groups_roles'->ig.name as role\n FROM instance_group ig\n INNER JOIN workspace_settings ws ON ws.auto_invite->'instance_groups' IS NOT NULL\n AND ws.auto_invite->'instance_groups' ? ig.name\n INNER JOIN workspace w ON w.id = ws.workspace_id AND w.deleted = false\n ORDER BY ig.name, ws.workspace_id\n ",
"describe": {
"columns": [
{
@@ -34,5 +34,5 @@
null
]
},
"hash": "1e6c125c884002a1565b11a2c308ce89f9726d21bbb3cc712ad0b6450cbb44e6"
"hash": "87cb0e9503776dbaea70652612cf43ecedc55b2e6319aefcf9797e7dfad0812c"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n workspace_settings\n SET\n success_handler = $1,\n success_handler_extra_args = $2\n WHERE\n workspace_id = $3\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Json",
"Text"
]
},
"nullable": []
},
"hash": "9044c71dc8aab7f5d17bf27c4702e67f3eee46d7dbccb09cadeaafa0534952d6"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET success_handler = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb",
"Text"
]
},
"nullable": []
},
"hash": "908ab9eda5ed0f3e76ea5a0e8a1714942358e2620f3bdfb080504ec1da332dbd"
}

View File

@@ -1,17 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n workspace_settings\n SET\n error_handler = $1,\n error_handler_extra_args = $2,\n error_handler_muted_on_cancel = $3\n WHERE\n workspace_id = $4\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Json",
"Bool",
"Text"
]
},
"nullable": []
},
"hash": "97b6e5779661343587c297b275df9e75fd22924ad2dbe124bb361f3e7fd8bfe0"
}

View File

@@ -31,7 +31,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -29,7 +29,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -154,7 +154,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = 'flow/f/test/success_flow'\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "a2bc410e1066ddc89ca4557ca0e29339e41cbc7a7ef6ad97b3f0eb93de04c359"
}

View File

@@ -184,7 +184,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -30,7 +30,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, auto_add_instance_groups_roles FROM workspace_settings WHERE $1 = ANY(COALESCE(auto_add_instance_groups, '{}'))",
"query": "\n SELECT workspace_id, auto_invite->'instance_groups_roles' as instance_groups_roles\n FROM workspace_settings\n WHERE auto_invite->'instance_groups' ? $1\n ",
"describe": {
"columns": [
{
@@ -10,7 +10,7 @@
},
{
"ordinal": 1,
"name": "auto_add_instance_groups_roles",
"name": "instance_groups_roles",
"type_info": "Jsonb"
}
],
@@ -21,8 +21,8 @@
},
"nullable": [
false,
true
null
]
},
"hash": "53210d19693ba46d97352b0ee321af59db453243c0cd17928ee942723d9cdc5c"
"hash": "acc9be5aa111985db14025ac0e0845031f65f214bbf1c599c3ee1d1e7ac0b50f"
}

View File

@@ -104,7 +104,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -159,7 +159,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -23,7 +23,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)\n VALUES ('test-workspace', 3001, 'u/operator/existing_script', 'export function main() { return \"original\"; }', 'deno', 'script', 'admin', '{}', 'Existing script', '', '', '{}')",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "be35e85e94641c71620e5402dcf74da8c73120b3e16194904575f79a4e055002"
}

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET error_handler = NULL WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "c0635f65d561c1a6b183b8fea45320482375d0bb5e617a9dd236a631a7b9ff05"
}

View File

@@ -1,118 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n -- slack_team_id,\n -- slack_name,\n -- slack_command_script,\n -- CASE WHEN slack_email = 'missing@email.xyz' THEN NULL ELSE slack_email END AS slack_email,\n auto_invite_domain IS NOT NULL AS \"auto_invite_enabled!\",\n CASE WHEN auto_invite_operator IS TRUE THEN 'operator' ELSE 'developer' END AS \"auto_invite_as!\",\n CASE WHEN auto_add IS TRUE THEN 'add' ELSE 'invite' END AS \"auto_invite_mode!\",\n webhook,\n deploy_to,\n error_handler,\n ai_config,\n error_handler_extra_args,\n error_handler_muted_on_cancel,\n large_file_storage,\n git_sync,\n default_app,\n default_scripts,\n workspace.name,\n mute_critical_alerts,\n color,\n operator_settings\n FROM workspace_settings\n LEFT JOIN workspace ON workspace.id = workspace_settings.workspace_id\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "auto_invite_enabled!",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "auto_invite_as!",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "auto_invite_mode!",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "webhook",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "deploy_to",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "error_handler",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "ai_config",
"type_info": "Jsonb"
},
{
"ordinal": 7,
"name": "error_handler_extra_args",
"type_info": "Json"
},
{
"ordinal": 8,
"name": "error_handler_muted_on_cancel",
"type_info": "Bool"
},
{
"ordinal": 9,
"name": "large_file_storage",
"type_info": "Jsonb"
},
{
"ordinal": 10,
"name": "git_sync",
"type_info": "Jsonb"
},
{
"ordinal": 11,
"name": "default_app",
"type_info": "Varchar"
},
{
"ordinal": 12,
"name": "default_scripts",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 14,
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 15,
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 16,
"name": "operator_settings",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null,
null,
null,
true,
true,
true,
true,
true,
false,
true,
true,
true,
true,
false,
true,
true,
true
]
},
"hash": "c12a0b0d423577afbb2772f971bffe2635785b53d31d0ceb3d72226a0c316e8a"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = '{\"path\": \"flow/f/test/success_flow\"}'::jsonb\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "c2f271bcea1f11b2979152cc743559236fd875192b7b7f4824c63675fdc6a551"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id FROM workspace_settings WHERE auto_add_instance_groups IS NOT NULL AND $1 = ANY(auto_add_instance_groups)",
"query": "SELECT workspace_id FROM workspace_settings WHERE auto_invite->'instance_groups' IS NOT NULL AND auto_invite->'instance_groups' ? $1",
"describe": {
"columns": [
{
@@ -18,5 +18,5 @@
false
]
},
"hash": "711c72a72298bb656882b35071e910dab721cda070f9c39bba3729bdc1467496"
"hash": "c7c0b7f760f9616ec4a18a8916226b65990f5055c1bc25eedefd303be75f553f"
}

View File

@@ -1,238 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n workspace_id,\n slack_team_id,\n teams_team_id,\n teams_team_name,\n teams_team_guid,\n slack_name,\n slack_command_script,\n teams_command_script,\n slack_email,\n slack_oauth_client_id,\n slack_oauth_client_secret,\n auto_invite_domain,\n auto_invite_operator,\n auto_add,\n customer_id,\n plan,\n webhook,\n deploy_to,\n ai_config,\n error_handler,\n error_handler_extra_args,\n error_handler_muted_on_cancel,\n success_handler,\n success_handler_extra_args,\n large_file_storage,\n datatable,\n ducklake,\n git_sync,\n deploy_ui,\n default_app,\n default_scripts,\n mute_critical_alerts,\n color,\n operator_settings,\n git_app_installations,\n auto_add_instance_groups,\n auto_add_instance_groups_roles\n FROM\n workspace_settings\n WHERE\n workspace_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "slack_team_id",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "teams_team_id",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "teams_team_name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "teams_team_guid",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "slack_name",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "slack_command_script",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "teams_command_script",
"type_info": "Text"
},
{
"ordinal": 8,
"name": "slack_email",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "slack_oauth_client_id",
"type_info": "Varchar"
},
{
"ordinal": 10,
"name": "slack_oauth_client_secret",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "auto_invite_domain",
"type_info": "Varchar"
},
{
"ordinal": 12,
"name": "auto_invite_operator",
"type_info": "Bool"
},
{
"ordinal": 13,
"name": "auto_add",
"type_info": "Bool"
},
{
"ordinal": 14,
"name": "customer_id",
"type_info": "Varchar"
},
{
"ordinal": 15,
"name": "plan",
"type_info": "Varchar"
},
{
"ordinal": 16,
"name": "webhook",
"type_info": "Text"
},
{
"ordinal": 17,
"name": "deploy_to",
"type_info": "Varchar"
},
{
"ordinal": 18,
"name": "ai_config",
"type_info": "Jsonb"
},
{
"ordinal": 19,
"name": "error_handler",
"type_info": "Varchar"
},
{
"ordinal": 20,
"name": "error_handler_extra_args",
"type_info": "Json"
},
{
"ordinal": 21,
"name": "error_handler_muted_on_cancel",
"type_info": "Bool"
},
{
"ordinal": 22,
"name": "success_handler",
"type_info": "Text"
},
{
"ordinal": 23,
"name": "success_handler_extra_args",
"type_info": "Json"
},
{
"ordinal": 24,
"name": "large_file_storage",
"type_info": "Jsonb"
},
{
"ordinal": 25,
"name": "datatable",
"type_info": "Jsonb"
},
{
"ordinal": 26,
"name": "ducklake",
"type_info": "Jsonb"
},
{
"ordinal": 27,
"name": "git_sync",
"type_info": "Jsonb"
},
{
"ordinal": 28,
"name": "deploy_ui",
"type_info": "Jsonb"
},
{
"ordinal": 29,
"name": "default_app",
"type_info": "Varchar"
},
{
"ordinal": 30,
"name": "default_scripts",
"type_info": "Jsonb"
},
{
"ordinal": 31,
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 32,
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 33,
"name": "operator_settings",
"type_info": "Jsonb"
},
{
"ordinal": 34,
"name": "git_app_installations",
"type_info": "Jsonb"
},
{
"ordinal": 35,
"name": "auto_add_instance_groups",
"type_info": "TextArray"
},
{
"ordinal": 36,
"name": "auto_add_instance_groups_roles",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true
]
},
"hash": "d0dfd217a4f53aaee7b83d5b5267f74e5ad617830dd835a45e17fd378bcbeada"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\",\n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\",\n EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS \"gcp_used!\",\n EXISTS(SELECT 1 FROM email_trigger WHERE workspace_id = $1) AS \"email_used!\"\n ",
"query": "\n SELECT\n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\",\n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\",\n EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS \"gcp_used!\",\n EXISTS(SELECT 1 FROM email_trigger WHERE workspace_id = $1) AS \"email_used!\",\n EXISTS(SELECT 1 FROM native_trigger WHERE workspace_id = $1 AND service_name = 'nextcloud'::native_trigger_service) AS \"nextcloud_used!\"\n ",
"describe": {
"columns": [
{
@@ -47,6 +47,11 @@
"ordinal": 8,
"name": "email_used!",
"type_info": "Bool"
},
{
"ordinal": 9,
"name": "nextcloud_used!",
"type_info": "Bool"
}
],
"parameters": {
@@ -63,8 +68,9 @@
null,
null,
null,
null,
null
]
},
"hash": "d1d9a3184f3470949840cc07414d08641527a4fe329204c65c49ab82d9ee4afb"
"hash": "d14e982c3d74499ec4bc62118e0edf065799eec5cf16f439b5f7568f392e60c3"
}

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET\n auto_invite = jsonb_set(\n jsonb_set(\n COALESCE(auto_invite, '{}'::jsonb),\n '{instance_groups}',\n (SELECT COALESCE(jsonb_agg(elem), '[]'::jsonb) FROM jsonb_array_elements(COALESCE(auto_invite->'instance_groups', '[]'::jsonb)) elem WHERE elem #>> '{}' != $1)\n ),\n '{instance_groups_roles}',\n COALESCE(auto_invite->'instance_groups_roles', '{}'::jsonb) - $1\n )\n WHERE auto_invite->'instance_groups' IS NOT NULL AND auto_invite->'instance_groups' ? $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "dab323eda1fcaff0435e98d77e544ed5d63dd6023b1dab77d5f188b299f03b9d"
}

View File

@@ -24,7 +24,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -23,7 +23,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n error_handler \n FROM \n workspace_settings \n WHERE \n workspace_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "error_handler",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "e03cfb65fc9b19c7e68e43d14a6e5041db783f1e6d545533a2d95f54e616b9fb"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = 'script/f/test/success_handler'\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "e3f2459d9ac3534531d5724bb2d67be6f33f8ca02ef4768bccd32a33a70a4300"
}

View File

@@ -184,7 +184,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET error_handler = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb",
"Text"
]
},
"nullable": []
},
"hash": "e844b9ee75a1b5438ffe743185fc78f649db89c78b2b8cd7e778bf18a6b41e67"
}

View File

@@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "SELECT success_handler->>'path' FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Text"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "e9808cc152e1ce4717260ebb42f203ca16321a4550073258734a6208b83c00c2"
}

View File

@@ -23,7 +23,8 @@
"sqs",
"mqtt",
"gcp",
"default_email"
"default_email",
"nextcloud"
]
}
}

View File

@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) FROM native_trigger WHERE workspace_id = $1 AND script_path = $2 AND is_flow = $3 AND service_name = 'nextcloud'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Bool"
]
},
"nullable": [
null
]
},
"hash": "f43a5c3eb04c04eb7d5f58e27d3fb6b979319a6507f3e317835e08a5ae33c5f3"
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT error_handler FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "error_handler",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "f8b34e09453d51d3df5be20652938a890ee353fec64ee73c312a3352da7f7515"
}

View File

@@ -104,7 +104,8 @@
"postgres",
"sqs",
"gcp",
"mqtt"
"mqtt",
"nextcloud"
]
}
}

View File

@@ -1,35 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, auto_invite_operator, auto_add FROM workspace_settings ws WHERE (auto_invite_domain = $1 OR auto_invite_domain = '*') AND NOT EXISTS (SELECT 1 FROM usr WHERE workspace_id = ws.workspace_id AND email = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "auto_invite_operator",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "auto_add",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false,
true,
true
]
},
"hash": "fc8fa909ef7a15c7ad30dd938be3c13864e855219c7f366c86f0605ec25d1538"
}

View File

@@ -7,6 +7,15 @@
- The API routes prefixes are all listed in windmill-api/src/lib.rs
- This repository is the open source side of the project. The enterprise files (\*\_ee.rs) are in the `windmill-ee-private` folder (a sibling directory). Those files are symlinked into their corresponding locations within each crate's `src/` directory.
## JSON Handling
- **Prefer `Box<serde_json::value::RawValue>` over `serde_json::Value`** when possible, especially:
- When storing JSON in the database (JSONB columns)
- When passing JSON through without modification
- When the JSON structure doesn't need to be inspected or manipulated
- This avoids unnecessary parsing/serialization overhead and preserves the original JSON format
- Use `serde_json::Value` only when you need to inspect, modify, or construct JSON programmatically
## Adding New Features
1. Update database schema with migration if necessary

579
backend/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.613.2"
version = "1.615.3"
authors.workspace = true
edition.workspace = true
@@ -35,7 +35,7 @@ members = [
exclude = ["./windmill-duckdb-ffi-internal"]
[workspace.package]
version = "1.613.2"
version = "1.615.3"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -77,7 +77,9 @@ websocket = ["windmill-api/websocket"]
http_trigger = ["windmill-api/http_trigger"]
postgres_trigger = ["windmill-api/postgres_trigger"]
mcp = ["windmill-api/mcp", "windmill-worker/mcp"]
bedrock = ["windmill-api/bedrock", "windmill-worker/bedrock", "windmill-common/bedrock"]
mqtt_trigger = ["windmill-api/mqtt_trigger"]
native_trigger = ["windmill-api/native_trigger"]
sqs_trigger = ["windmill-api/sqs_trigger", "windmill-common/aws_auth", "windmill-api/openidconnect"]
gcp_trigger = ["windmill-api/gcp_trigger"]
smtp = ["windmill-api/smtp", "windmill-common/smtp", "windmill-queue/smtp"]
@@ -106,7 +108,7 @@ all_languages_windows = ["python", "deno_core", "rust", "mysql", "oracledb", "du
all_sqlx_features = ["all_languages", "enterprise", "enterprise_saml", "embedding", "parquet", "prometheus", "flow_testing",
"openidconnect", "cloud", "jemalloc", "tantivy", "sqlx", "kafka", "nats", "otel", "dind", "websocket", "http_trigger",
"postgres_trigger", "mcp", "mqtt_trigger", "sqs_trigger", "gcp_trigger", "smtp", "stripe",
"license", "oauth2", "zip", "static_frontend", "scoped_cache", "agent_worker_server"]
"license", "oauth2", "zip", "static_frontend", "scoped_cache", "agent_worker_server", "bedrock"]
[patch.crates-io]
object_store = { git = "https://github.com/apache/arrow-rs-object-store", rev = "36752c975d4f29e20b57c91f81a10872dcd48ae7" }
@@ -151,8 +153,6 @@ memchr.workspace = true
v8 = { workspace = true, optional = true }
rustls.workspace = true
pep440_rs.workspace = true
systemstat.workspace = true
size.workspace = true
strum.workspace = true
aws-sigv4.workspace = true
aws-sdk-config.workspace = true
@@ -162,7 +162,7 @@ libloading.workspace = true
bitflags.workspace = true
globset.workspace = true
opentelemetry-proto.workspace = true
systemstat.workspace = true
[target.'cfg(windows)'.dependencies]
windows-service = "0.7"
@@ -337,8 +337,8 @@ futures-core = "^0"
lazy_static = "1.4.0"
serde_derive = "1.0.147"
const_format = { version = "0.2.35", features = ["rust_1_64", "rust_1_51"] }
const-str = "0.5"
constant_time_eq = "0.3.1"
dyn-iter = "0.2.0"
rsa = "^0"
async_zip = { version = "0.0.17", features = ["tokio", "tokio-fs", "deflate", "chrono"] }
once_cell = "1.17.1"
@@ -382,6 +382,7 @@ openssl = "=0.10"
mail-parser = "^0"
matchit = "=0.7.3"
rdkafka = { version = "0.36.2", features = ["cmake-build", "ssl-vendored"] }
rdkafka-sys = "=4.9.0"
pg_escape = "0.1.1"
async-nats = "0.38.0"
nkeys = "0.4.4"
@@ -395,7 +396,8 @@ datafusion = "47.0.0"
object_store = { git = "https://github.com/apache/arrow-rs-object-store", rev = "36752c975d4f29e20b57c91f81a10872dcd48ae7", features = ["aws", "azure", "gcp"] }
openidconnect = { version = "4.0.0-rc.1" }
aws-config = "^1"
aws-sdk-bedrockruntime = "=1.113.0"
aws-sdk-bedrock = "1.129.0"
aws-sdk-bedrockruntime = "=1.122.0"
aws-credential-types = "^1"
aws-smithy-types = "^1"
aws-sdk-sqs = "=1.77.0"
@@ -404,7 +406,8 @@ aws-sdk-sso = "=1.77.0"
aws-sdk-ssooidc = "=1.78.0"
rustls = "=0.23.35"
async-once-cell = "0.5.4"
systemstat = "0.2.4"
size = "0.5.0"
aws-smithy-types-convert = { version = "^0", features = ["convert-chrono"] }
crc = "^3"
@@ -436,8 +439,6 @@ pin-project-lite = "^0"
tantivy = { git="https://github.com/windmill-labs/tantivy", rev="6a24621231202ccd77bec90d8787e2281fb94e4e" }
backon = "1.3.0"
systemstat = "0.2.4"
size = "0.5.0"
flume = { version = "0.11.1", features = ["async"] }
kube = { version = "1.1.0", features = ["runtime", "derive"] }

View File

@@ -1 +1 @@
cfed5d823884d9c8235ac4d8aeed0b71d5a53592
bcf3ceab92be635e65f59c0ca0e3c64d8c2f6928

View File

@@ -0,0 +1,7 @@
-- Add down migration script here
DROP TABLE IF EXISTS native_trigger;
DROP TABLE IF EXISTS workspace_integrations;
DROP TYPE IF EXISTS native_trigger_service;

View File

@@ -0,0 +1,52 @@
-- Add up migration script here
CREATE TYPE native_trigger_service AS ENUM ('nextcloud');
ALTER TYPE TRIGGER_KIND ADD VALUE IF NOT EXISTS 'nextcloud';
ALTER TYPE job_trigger_kind ADD VALUE IF NOT EXISTS 'nextcloud';
CREATE TABLE native_trigger (
external_id VARCHAR(255) NOT NULL,
workspace_id VARCHAR(50) NOT NULL,
service_name native_trigger_service NOT NULL,
script_path VARCHAR(255) NOT NULL,
is_flow BOOLEAN NOT NULL,
webhook_token_prefix VARCHAR(10) NOT NULL,
service_config JSONB,
error TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (external_id, workspace_id, service_name),
CONSTRAINT fk_native_trigger_workspace FOREIGN KEY (workspace_id)
REFERENCES workspace(id) ON DELETE CASCADE
);
CREATE INDEX idx_native_trigger_workspace
ON native_trigger (workspace_id);
CREATE INDEX idx_native_trigger_script_path
ON native_trigger (workspace_id, script_path, is_flow);
GRANT ALL ON native_trigger TO windmill_user;
GRANT ALL ON native_trigger TO windmill_admin;
CREATE TABLE workspace_integrations (
workspace_id VARCHAR(50) NOT NULL,
service_name native_trigger_service NOT NULL,
oauth_data JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by VARCHAR(50) NOT NULL,
PRIMARY KEY (workspace_id, service_name),
CONSTRAINT fk_workspace_integrations_workspace FOREIGN KEY (workspace_id)
REFERENCES workspace(id) ON DELETE CASCADE
);
CREATE INDEX idx_workspace_integrations_workspace
ON workspace_integrations (workspace_id);
CREATE INDEX idx_workspace_integrations_service
ON workspace_integrations (service_name);
GRANT ALL ON workspace_integrations TO windmill_user;
GRANT ALL ON workspace_integrations TO windmill_admin;

View File

@@ -0,0 +1,46 @@
-- Step 0: Drop the GIN index on auto_invite
DROP INDEX IF EXISTS idx_workspace_settings_auto_invite;
-- Step 1: Rename current JSONB columns to temporary names to avoid collision
ALTER TABLE workspace_settings
RENAME COLUMN error_handler TO error_handler_jsonb;
ALTER TABLE workspace_settings
RENAME COLUMN success_handler TO success_handler_jsonb;
-- Step 2: Restore old columns with original names and types
ALTER TABLE workspace_settings
ADD COLUMN IF NOT EXISTS auto_invite_domain VARCHAR(255),
ADD COLUMN IF NOT EXISTS auto_invite_operator BOOLEAN,
ADD COLUMN IF NOT EXISTS auto_add BOOLEAN,
ADD COLUMN IF NOT EXISTS auto_add_instance_groups TEXT[],
ADD COLUMN IF NOT EXISTS auto_add_instance_groups_roles JSONB,
ADD COLUMN IF NOT EXISTS error_handler VARCHAR(255),
ADD COLUMN IF NOT EXISTS error_handler_extra_args JSON,
ADD COLUMN IF NOT EXISTS error_handler_muted_on_cancel BOOLEAN DEFAULT false,
ADD COLUMN IF NOT EXISTS error_handler_muted_on_user_path BOOLEAN DEFAULT false,
ADD COLUMN IF NOT EXISTS success_handler TEXT,
ADD COLUMN IF NOT EXISTS success_handler_extra_args JSON;
-- Step 3: Migrate data back from JSONB columns to flat columns
UPDATE workspace_settings SET
auto_invite_domain = auto_invite->>'domain',
auto_invite_operator = COALESCE((auto_invite->>'operator')::boolean, false),
auto_add = (auto_invite->>'mode') = 'add',
auto_add_instance_groups = CASE
WHEN auto_invite->'instance_groups' IS NOT NULL AND auto_invite->'instance_groups' != 'null'::jsonb
THEN ARRAY(SELECT jsonb_array_elements_text(auto_invite->'instance_groups'))
ELSE NULL
END,
auto_add_instance_groups_roles = auto_invite->'instance_groups_roles',
error_handler = error_handler_jsonb->>'path',
error_handler_extra_args = (error_handler_jsonb->'extra_args')::json,
error_handler_muted_on_cancel = COALESCE((error_handler_jsonb->>'muted_on_cancel')::boolean, false),
error_handler_muted_on_user_path = COALESCE((error_handler_jsonb->>'muted_on_user_path')::boolean, false),
success_handler = success_handler_jsonb->>'path',
success_handler_extra_args = (success_handler_jsonb->'extra_args')::json;
-- Step 4: Drop the JSONB columns
ALTER TABLE workspace_settings
DROP COLUMN IF EXISTS auto_invite,
DROP COLUMN IF EXISTS error_handler_jsonb,
DROP COLUMN IF EXISTS success_handler_jsonb;

View File

@@ -0,0 +1,59 @@
-- Step 1: Add error_handler_muted_on_user_path column if it doesn't exist (was previously a separate migration)
ALTER TABLE workspace_settings ADD COLUMN IF NOT EXISTS error_handler_muted_on_user_path BOOL NOT NULL DEFAULT false;
-- Step 2: Add new JSONB columns with temporary names (to avoid collision with existing TEXT columns)
ALTER TABLE workspace_settings
ADD COLUMN IF NOT EXISTS auto_invite JSONB,
ADD COLUMN IF NOT EXISTS error_handler_new JSONB,
ADD COLUMN IF NOT EXISTS success_handler_new JSONB;
-- Step 3: Migrate existing data to new columns (use jsonb_strip_nulls to omit null values)
UPDATE workspace_settings SET
auto_invite = jsonb_strip_nulls(jsonb_build_object(
'enabled', auto_invite_domain IS NOT NULL,
'domain', auto_invite_domain,
'operator', COALESCE(auto_invite_operator, false),
'mode', CASE WHEN auto_add THEN 'add' ELSE 'invite' END,
'instance_groups', CASE WHEN auto_add_instance_groups IS NOT NULL THEN to_jsonb(auto_add_instance_groups) ELSE NULL END,
'instance_groups_roles', auto_add_instance_groups_roles
)),
error_handler_new = CASE
WHEN error_handler IS NOT NULL THEN jsonb_strip_nulls(jsonb_build_object(
'path', error_handler,
'extra_args', error_handler_extra_args::jsonb,
'muted_on_cancel', error_handler_muted_on_cancel,
'muted_on_user_path', error_handler_muted_on_user_path
))
ELSE NULL
END,
success_handler_new = CASE
WHEN success_handler IS NOT NULL THEN jsonb_strip_nulls(jsonb_build_object(
'path', success_handler,
'extra_args', success_handler_extra_args::jsonb
))
ELSE NULL
END;
-- Step 4: Drop old columns that are now consolidated
ALTER TABLE workspace_settings
DROP COLUMN IF EXISTS auto_invite_domain,
DROP COLUMN IF EXISTS auto_invite_operator,
DROP COLUMN IF EXISTS auto_add,
DROP COLUMN IF EXISTS auto_add_instance_groups,
DROP COLUMN IF EXISTS auto_add_instance_groups_roles,
DROP COLUMN IF EXISTS error_handler,
DROP COLUMN IF EXISTS error_handler_extra_args,
DROP COLUMN IF EXISTS error_handler_muted_on_cancel,
DROP COLUMN IF EXISTS error_handler_muted_on_user_path,
DROP COLUMN IF EXISTS success_handler,
DROP COLUMN IF EXISTS success_handler_extra_args;
-- Step 5: Rename new columns to their final names
ALTER TABLE workspace_settings
RENAME COLUMN error_handler_new TO error_handler;
ALTER TABLE workspace_settings
RENAME COLUMN success_handler_new TO success_handler;
-- Step 6: Add GIN index on auto_invite for efficient JSONB queries (e.g., ? operator for instance_groups)
-- Using default GIN opclass (not jsonb_path_ops) to support the ? operator
CREATE INDEX IF NOT EXISTS idx_workspace_settings_auto_invite ON workspace_settings USING GIN (auto_invite);

View File

@@ -0,0 +1,3 @@
-- This migration cannot be reversed.
-- The v2 compatibility layer has been permanently removed.
DO $$ BEGIN RAISE EXCEPTION 'Cannot reverse v2 finalization migration'; END $$;

View File

@@ -0,0 +1,97 @@
-- V2 Migration Finalization
-- This migration finalizes the v2 job table migration by removing the compatibility layer.
-- Skip if live migration already ran (indicated by 'v2_finalize_job_completed' in windmill_migrations).
DO $$
BEGIN
-- Check if live migration already completed this work
IF EXISTS (SELECT 1 FROM windmill_migrations WHERE name = 'v2_finalize_job_completed') THEN
RAISE NOTICE 'v2_finalize already done via live migration, skipping';
RETURN;
END IF;
-- 1. Disable RLS on v2 tables (no-op if already disabled)
ALTER TABLE v2_job_queue DISABLE ROW LEVEL SECURITY;
ALTER TABLE v2_job_completed DISABLE ROW LEVEL SECURITY;
-- 2. Drop sync functions (CASCADE drops associated triggers)
DROP FUNCTION IF EXISTS v2_job_after_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_after_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_completed_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_completed_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_runtime_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_runtime_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_status_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_status_before_update CASCADE;
-- 3. Drop compatibility views
DROP VIEW IF EXISTS completed_job CASCADE;
DROP VIEW IF EXISTS completed_job_view CASCADE;
DROP VIEW IF EXISTS job CASCADE;
DROP VIEW IF EXISTS queue CASCADE;
DROP VIEW IF EXISTS queue_view CASCADE;
-- 4. Drop __ columns from v2_job_queue
ALTER TABLE v2_job_queue
DROP COLUMN IF EXISTS __parent_job CASCADE,
DROP COLUMN IF EXISTS __created_by CASCADE,
DROP COLUMN IF EXISTS __script_hash CASCADE,
DROP COLUMN IF EXISTS __script_path CASCADE,
DROP COLUMN IF EXISTS __args CASCADE,
DROP COLUMN IF EXISTS __logs CASCADE,
DROP COLUMN IF EXISTS __raw_code CASCADE,
DROP COLUMN IF EXISTS __canceled CASCADE,
DROP COLUMN IF EXISTS __last_ping CASCADE,
DROP COLUMN IF EXISTS __job_kind CASCADE,
DROP COLUMN IF EXISTS __env_id CASCADE,
DROP COLUMN IF EXISTS __schedule_path CASCADE,
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
DROP COLUMN IF EXISTS __flow_status CASCADE,
DROP COLUMN IF EXISTS __raw_flow CASCADE,
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
DROP COLUMN IF EXISTS __language CASCADE,
DROP COLUMN IF EXISTS __same_worker CASCADE,
DROP COLUMN IF EXISTS __raw_lock CASCADE,
DROP COLUMN IF EXISTS __pre_run_error CASCADE,
DROP COLUMN IF EXISTS __email CASCADE,
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
DROP COLUMN IF EXISTS __mem_peak CASCADE,
DROP COLUMN IF EXISTS __root_job CASCADE,
DROP COLUMN IF EXISTS __leaf_jobs CASCADE,
DROP COLUMN IF EXISTS __concurrent_limit CASCADE,
DROP COLUMN IF EXISTS __concurrency_time_window_s CASCADE,
DROP COLUMN IF EXISTS __timeout CASCADE,
DROP COLUMN IF EXISTS __flow_step_id CASCADE,
DROP COLUMN IF EXISTS __cache_ttl CASCADE;
-- 5. Drop __ columns from v2_job_completed
ALTER TABLE v2_job_completed
DROP COLUMN IF EXISTS __parent_job CASCADE,
DROP COLUMN IF EXISTS __created_by CASCADE,
DROP COLUMN IF EXISTS __created_at CASCADE,
DROP COLUMN IF EXISTS __success CASCADE,
DROP COLUMN IF EXISTS __script_hash CASCADE,
DROP COLUMN IF EXISTS __script_path CASCADE,
DROP COLUMN IF EXISTS __args CASCADE,
DROP COLUMN IF EXISTS __logs CASCADE,
DROP COLUMN IF EXISTS __raw_code CASCADE,
DROP COLUMN IF EXISTS __canceled CASCADE,
DROP COLUMN IF EXISTS __job_kind CASCADE,
DROP COLUMN IF EXISTS __env_id CASCADE,
DROP COLUMN IF EXISTS __schedule_path CASCADE,
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
DROP COLUMN IF EXISTS __raw_flow CASCADE,
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
DROP COLUMN IF EXISTS __language CASCADE,
DROP COLUMN IF EXISTS __is_skipped CASCADE,
DROP COLUMN IF EXISTS __raw_lock CASCADE,
DROP COLUMN IF EXISTS __email CASCADE,
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
DROP COLUMN IF EXISTS __tag CASCADE,
DROP COLUMN IF EXISTS __priority CASCADE;
-- Mark as done in windmill_migrations for consistency
INSERT INTO windmill_migrations (name) VALUES ('v2_finalize_job_completed') ON CONFLICT DO NOTHING;
END $$;

View File

@@ -16,7 +16,7 @@ use monitor::{
send_current_log_file_to_object_store, send_logs_to_object_store, WORKERS_NAMES,
};
use rand::Rng;
use sqlx::postgres::PgListener;
use sqlx::{postgres::PgListener, Pool, Postgres};
use std::{
collections::HashMap,
fs::{create_dir_all, DirBuilder},
@@ -35,7 +35,6 @@ use windmill_common::ee_oss::{
use windmill_common::{
agent_workers::build_agent_http_client,
get_database_url,
global_settings::{
APP_WORKSPACED_ROUTE_SETTING, BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING,
CRITICAL_ALERTS_ON_DB_OVERSIZE_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING,
@@ -60,9 +59,10 @@ use windmill_common::{
MODE_AND_ADDONS,
},
worker::{
reload_custom_tags_setting, Connection, HUB_CACHE_DIR, TMP_DIR, TMP_LOGS_DIR, WORKER_GROUP,
reload_custom_tags_setting, Connection, HUB_CACHE_DIR, HUB_RT_CACHE_DIR, TMP_DIR,
TMP_LOGS_DIR, WORKER_GROUP,
},
KillpillSender, METRICS_ENABLED,
KillpillSender, DEFAULT_HUB_BASE_URL, METRICS_ENABLED,
};
#[cfg(feature = "enterprise")]
@@ -110,7 +110,10 @@ use windmill_common::s3_helpers::reload_object_store_setting;
const DEFAULT_NUM_WORKERS: usize = 1;
const DEFAULT_PORT: u16 = 8000;
const DEFAULT_SERVER_BIND_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
const DEFAULT_WORKER_BIND_ADDR: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
const BIND_ADDR_ENV: &str = "SERVER_BIND_ADDR";
#[cfg(target_os = "linux")]
mod cgroups;
#[cfg(feature = "private")]
pub mod ee;
@@ -320,6 +323,160 @@ async fn cache_hub_scripts(file_path: Option<String>) -> anyhow::Result<()> {
Ok(())
}
/// Raw resource type from hub API (schema is a JSON string)
#[derive(serde::Deserialize)]
struct HubResourceTypeRaw {
pub id: i64,
pub name: String,
pub schema: Option<String>,
pub app: String,
pub description: Option<String>,
}
/// Processed resource type with parsed schema
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub struct HubResourceType {
pub id: i64,
pub name: String,
pub schema: Option<serde_json::Value>,
pub app: String,
pub description: Option<String>,
}
const HUB_RT_CACHE_FILE: &str = "resource_types.json";
async fn cache_hub_resource_types() -> anyhow::Result<()> {
println!("Caching resource types from hub...");
let response = HTTP_CLIENT
.get(format!("{}/resource_types/list", DEFAULT_HUB_BASE_URL))
.header("Accept", "application/json")
.send()
.await
.with_context(|| "Failed to fetch resource types from hub")?;
if !response.status().is_success() {
anyhow::bail!(
"Failed to fetch resource types from hub: {}",
response.status()
);
}
let raw_types: Vec<HubResourceTypeRaw> = response
.json::<Vec<HubResourceTypeRaw>>()
.await
.with_context(|| "Failed to parse resource types from hub")?;
// Parse schema strings into JSON values
let resource_types: Vec<HubResourceType> = raw_types
.into_iter()
.filter_map(|rt| {
let schema = match rt.schema {
Some(s) => match serde_json::from_str(&s) {
Ok(v) => Some(v),
Err(e) => {
println!("Warning: failed to parse schema for {}: {}", rt.name, e);
return None;
}
},
None => None,
};
Some(HubResourceType {
id: rt.id,
name: rt.name,
schema,
app: rt.app,
description: rt.description,
})
})
.collect();
println!("Fetched {} resource types from hub", resource_types.len());
create_dir_all(HUB_RT_CACHE_DIR)?;
let cache_path = format!("{}/{}", HUB_RT_CACHE_DIR, HUB_RT_CACHE_FILE);
let content = serde_json::to_string_pretty(&resource_types)
.with_context(|| "Failed to serialize resource types")?;
std::fs::write(&cache_path, content)
.with_context(|| format!("Failed to write cache file to {}", cache_path))?;
println!("Cached resource types to {}", cache_path);
Ok(())
}
pub async fn sync_cached_resource_types(db: &sqlx::Pool<sqlx::Postgres>) -> anyhow::Result<()> {
let cache_path = format!("{}/{}", HUB_RT_CACHE_DIR, HUB_RT_CACHE_FILE);
if tokio::fs::metadata(&cache_path).await.is_err() {
tracing::info!("No cached resource types found at {}, skipping sync", cache_path);
return Ok(());
}
tracing::info!("Syncing cached resource types to admins workspace...");
let content = tokio::fs::read_to_string(&cache_path)
.await
.with_context(|| format!("Failed to read cache file from {}", cache_path))?;
let cached_types: Vec<HubResourceType> = serde_json::from_str(&content)
.with_context(|| "Failed to parse cached resource types")?;
tracing::info!("Found {} cached resource types", cached_types.len());
// Get existing resource types in admins workspace
let existing_types: Vec<(String, Option<serde_json::Value>, Option<String>)> = sqlx::query_as(
"SELECT name, schema, description FROM resource_type WHERE workspace_id = 'admins'",
)
.fetch_all(db)
.await
.with_context(|| "Failed to fetch existing resource types")?;
let existing_map: std::collections::HashMap<String, (Option<serde_json::Value>, Option<String>)> =
existing_types
.into_iter()
.map(|(name, schema, desc)| (name, (schema, desc)))
.collect();
let mut synced_count = 0;
let mut skipped_count = 0;
for rt in cached_types {
// Check if resource type already exists with same schema and description
if let Some((existing_schema, existing_desc)) = existing_map.get(&rt.name) {
if existing_schema == &rt.schema && existing_desc == &rt.description {
skipped_count += 1;
continue;
}
}
// Insert or update resource type
sqlx::query(
"INSERT INTO resource_type (workspace_id, name, schema, description, edited_at)
VALUES ('admins', $1, $2, $3, now())
ON CONFLICT (workspace_id, name) DO UPDATE
SET schema = EXCLUDED.schema, description = EXCLUDED.description, edited_at = now()",
)
.bind(&rt.name)
.bind(&rt.schema)
.bind(&rt.description)
.execute(db)
.await
.with_context(|| format!("Failed to upsert resource type {}", rt.name))?;
synced_count += 1;
}
tracing::info!(
"Synced {} resource types to admins workspace ({} skipped as unchanged)",
synced_count,
skipped_count
);
Ok(())
}
fn print_help() {
println!("Windmill - a fast, open-source workflow engine and job runner.");
println!();
@@ -330,13 +487,14 @@ fn print_help() {
println!(" help | -h | --help Show this help information and exit");
println!(" version Show Windmill version and exit");
println!(" cache [hubPaths.json] Pre-cache hub scripts (default: ./hubPaths.json)");
println!(" cache-rt Pre-cache hub resource types");
println!();
println!("Environment variables (name = default):");
println!(" DATABASE_URL = <required> The Postgres database url.");
println!(" MODE = standalone Mode: standalone | worker | server | agent");
println!(" BASE_URL = http://localhost:8000 Public base URL of your instance (overridden by instance settings)");
println!(" PORT = {} HTTP port (server/indexer/MCP modes)", DEFAULT_PORT);
println!(" SERVER_BIND_ADDR = {} IP to bind the server to", DEFAULT_SERVER_BIND_ADDR);
println!(" SERVER_BIND_ADDR = <mode dependent> IP to bind to (server: {}, worker: {})", DEFAULT_SERVER_BIND_ADDR, DEFAULT_WORKER_BIND_ADDR);
println!(" NUM_WORKERS = {} Number of workers (standalone/worker modes)", DEFAULT_NUM_WORKERS);
println!(" WORKER_GROUP = default Worker group this worker belongs to",);
println!(" JSON_FMT = false Output logs in JSON instead of logfmt");
@@ -345,6 +503,7 @@ fn print_help() {
println!(" LICENSE_KEY = None (EE only) Enterprise license key (workers require valid key)");
println!(" RUN_UPDATE_CA_CERTIFICATE_AT_START = false Run system CA update at startup");
println!(" RUN_UPDATE_CA_CERTIFICATE_PATH = /usr/sbin/update-ca-certificates Path to CA update tool");
println!(" SYNC_CACHED_RT = false Sync cached resource types to admins workspace on server start");
println!();
println!("Notes:");
println!("- Advanced and less commonly used settings are managed via the database and are omitted here.");
@@ -439,6 +598,10 @@ async fn windmill_main() -> anyhow::Result<()> {
windmill_worker::run_prepare_deps_cli().await?;
return Ok(());
}
"cache-rt" => {
cache_hub_resource_types().await?;
return Ok(());
}
_ => {}
}
@@ -468,14 +631,15 @@ async fn windmill_main() -> anyhow::Result<()> {
let indexer_mode = mode == Mode::Indexer;
let mcp_mode = mode == Mode::MCP;
let server_bind_address: IpAddr = if server_mode || indexer_mode || mcp_mode {
std::env::var("SERVER_BIND_ADDR")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(IpAddr::from(DEFAULT_SERVER_BIND_ADDR))
let default_bind_addr = if server_mode || indexer_mode || mcp_mode {
DEFAULT_SERVER_BIND_ADDR
} else {
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))
DEFAULT_WORKER_BIND_ADDR
};
let server_bind_address: IpAddr = std::env::var(BIND_ADDR_ENV)
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(IpAddr::from(default_bind_addr));
let (conn, first_suffix) = if mode == Mode::Agent {
tracing::info!(
@@ -543,6 +707,17 @@ async fn windmill_main() -> anyhow::Result<()> {
} else {
tracing::info!("SKIP_MIGRATION set, skipping db migration...")
}
// Sync cached resource types to admins workspace if SYNC_CACHED_RT is set
if std::env::var("SYNC_CACHED_RT")
.ok()
.map(|v| v.to_lowercase() == "true" || v == "1")
.unwrap_or(false)
{
if let Err(e) = sync_cached_resource_types(db).await {
tracing::warn!("Failed to sync cached resource types: {:#}", e);
}
}
}
}
@@ -901,10 +1076,9 @@ Windmill Community Edition {GIT_VERSION}
match conn {
Connection::Sql(ref db) => {
let base_internal_url = base_internal_url.to_string();
let db_url = get_database_url().await?;
let db = db.clone();
let h = tokio::spawn(async move {
let mut listener = retry_listen_pg(&db_url.as_str().await).await;
let mut listener = retry_listen_pg(&db).await;
let mut last_listener_refresh = Instant::now();
let mut monitor_iteration: u64 = 0;
let rd_shift: u8 = rand::rng().random_range(0..200);
@@ -1245,14 +1419,14 @@ Windmill Community Edition {GIT_VERSION}
},
Err(e) => {
tracing::error!(error = %e, "Could not receive notification, attempting to reconnect listener");
let db_url = db_url.clone();
let db = db.clone();
tokio::select! {
biased;
_ = monitor_killpill_rx.recv() => {
tracing::info!("received killpill for monitor job");
break;
},
new_listener = async move { retry_listen_pg(&db_url.as_str().await).await } => {
new_listener = async move { retry_listen_pg(&db).await } => {
listener = new_listener;
continue;
}
@@ -1266,7 +1440,7 @@ Windmill Community Edition {GIT_VERSION}
if let Err(e) = listener.unlisten_all().await {
tracing::error!(error = %e, "Could not unlisten to database");
}
listener = retry_listen_pg(&db_url.as_str().await).await;
listener = retry_listen_pg(&db).await;
initial_load(
&conn,
tx.clone(),
@@ -1341,7 +1515,8 @@ Windmill Community Edition {GIT_VERSION}
// update min version explicitly.
// for sql connection it is the part of monitor_db.
windmill_common::worker::update_min_version(conn).await;
// TODO: pass worker names for min keep-alive alerts (for HTTP connection)
windmill_common::min_version::update_min_version(conn, true, vec![], false).await;
}
};
}
@@ -1450,8 +1625,8 @@ Windmill Community Edition {GIT_VERSION}
std::process::exit(0);
}
async fn listen_pg(url: &str) -> Option<PgListener> {
let mut listener = match PgListener::connect(url).await {
async fn listen_pg(db: &Pool<Postgres>) -> Option<PgListener> {
let mut listener = match PgListener::connect_with(db).await {
Ok(l) => l,
Err(e) => {
tracing::error!(error = %e, "Could not connect to database");
@@ -1484,13 +1659,13 @@ async fn listen_pg(url: &str) -> Option<PgListener> {
return Some(listener);
}
async fn retry_listen_pg(url: &str) -> PgListener {
let mut listener = listen_pg(url).await;
async fn retry_listen_pg(db: &Pool<Postgres>) -> PgListener {
let mut listener = listen_pg(db).await;
loop {
if listener.is_none() {
tracing::info!("Retrying listening to pg listen in 5 seconds");
tokio::time::sleep(Duration::from_secs(5)).await;
listener = listen_pg(url).await;
listener = listen_pg(db).await;
} else {
tracing::info!("Successfully connected to pg listen");
return listener.unwrap();

View File

@@ -29,6 +29,9 @@ use windmill_api::{
SCIM_TOKEN,
};
#[cfg(feature = "native_trigger")]
use windmill_api::native_triggers::sync::sync_all_triggers;
#[cfg(feature = "enterprise")]
use windmill_common::ee_oss::low_disk_alerts;
#[cfg(feature = "enterprise")]
@@ -219,6 +222,7 @@ pub async fn initial_load(
e
)
}
windmill_common::min_version::store_min_keep_alive_version(db).await;
}
}
@@ -1863,7 +1867,35 @@ pub async fn monitor_db(
let update_min_worker_version_f = async {
#[cfg(not(feature = "test_job_debouncing"))]
windmill_common::worker::update_min_version(conn).await;
windmill_common::min_version::update_min_version(conn, _worker_mode, WORKERS_NAMES.read().await.clone(), initial_load).await;
};
// Run every 5 minutes (10 iterations * 30s = 5 minutes)
let native_triggers_sync_f = async {
#[cfg(feature = "native_trigger")]
if server_mode && iteration.is_some() && iteration.as_ref().unwrap().should_run(10) {
if let Some(db) = conn.as_sql() {
match sync_all_triggers(db).await {
Ok(result) => {
tracing::debug!(
"Native triggers sync completed: {} workspaces, {} synced, {} errors",
result.workspaces_processed,
result.total_synced,
result.total_errors
);
if result.total_errors > 0 {
tracing::warn!(
"Native triggers sync encountered {} errors",
result.total_errors
);
}
}
Err(e) => {
tracing::error!("Error during native triggers sync: {:#}", e);
}
}
}
}
};
join!(
@@ -1884,6 +1916,7 @@ pub async fn monitor_db(
cleanup_debounce_keys_completed_f,
cleanup_flow_iterator_data_f,
cleanup_worker_group_stats_f,
native_triggers_sync_f,
);
}
@@ -2098,7 +2131,6 @@ pub async fn load_base_url(conn: &Connection) -> error::Result<String> {
} else {
std_base_url
};
{
let mut l = BASE_URL.write().await;
*l = base_url.clone();
@@ -2951,8 +2983,8 @@ RETURNING key,job_id
async fn cleanup_debounce_keys_for_completed_jobs(db: &DB) -> error::Result<()> {
// If min version doesn't support runnable settings, clean up debounce keys for completed jobs
if !*windmill_common::worker::MIN_VERSION_SUPPORTS_RUNNABLE_SETTINGS_V0
.read()
if !windmill_common::min_version::MIN_VERSION_SUPPORTS_RUNNABLE_SETTINGS_V0
.met()
.await
{
let result = sqlx::query!(

View File

@@ -1,12 +1,11 @@
#![allow(dead_code)]
use std::{future::Future, str::FromStr, sync::Arc};
use std::{future::Future, str::FromStr};
use futures::Stream;
use serde::Serialize;
use serde_json::json;
use sqlx::{postgres::PgListener, Pool, Postgres};
use tokio::sync::RwLock;
use uuid::Uuid;
use windmill_api_client::types::NewScript;
#[cfg(feature = "python")]
@@ -498,11 +497,11 @@ pub async fn initialize_tracing() {
}
pub async fn test_for_versions<F: Future<Output = ()>>(
version_flags: impl Iterator<Item = Arc<RwLock<bool>>>,
constraints: impl Iterator<Item = &'static windmill_common::min_version::VersionConstraint>,
test: impl Fn() -> F,
) {
for version_flag in version_flags {
*version_flag.write().await = true;
for constraint in constraints {
*windmill_common::min_version::MIN_VERSION.write().await = constraint.version().clone();
test().await;
}
}

Some files were not shown because too many files have changed in this diff Show More