Compare commits

...

38 Commits

Author SHA1 Message Date
Alexander Petric
387a0c854d fix: pipeline RESET ALL with first query via tokio::join
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-03 20:41:48 +00:00
Alexander Petric
43d2cf4522 fix: move RESET ALL inside result_f async block
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-03 20:33:13 +00:00
Alexander Petric
3f55f226c3 Merge branch 'main' into alp/postgres_state_reset 2026-04-03 16:02:37 -04:00
Alexander Petric
1904ffcaaa fix: reset postgres session state on cached connection reuse
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-03 20:00:21 +00:00
Ruben Fiszel
18eb6e0df7 point to latest otel 2026-04-03 19:59:30 +00:00
Ruben Fiszel
adc9fe722d fix: gate relock_skip tests on private feature and update ee-repo-ref (#8703)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 19:58:54 +00:00
Ruben Fiszel
0aea49f960 feat: add http/protobuf support for OTEL exporters (#8702)
* feat: add --main flag to write_latest_ee_ref.sh to point to latest EE main

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [ee] feat: add http/protobuf support for OTEL exporters

Add http-proto and reqwest-client features to opentelemetry-otlp to
enable HTTP/protobuf transport as an alternative to gRPC.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref.txt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: expose OTEL protocol selector in instance settings UI

Replace the hardcoded "gRPC" label with a dropdown allowing users to
select between grpc (default) and http/protobuf.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 681b725781611510ed3040c00e8f9b8497d6feda

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

Previous ee-repo-ref: 50051ded8183e662a9e932d87d17258501f3e944

New ee-repo-ref: 681b725781611510ed3040c00e8f9b8497d6feda

Automated by sync-ee-ref workflow.

* fix: remove reqwest-client feature to avoid conflict with default reqwest-blocking-client

The opentelemetry-otlp crate only activates the reqwest-client HTTP client
when reqwest-blocking-client is NOT also enabled. Since the default features
include reqwest-blocking-client, having both resulted in no HTTP client being
created. The default reqwest-blocking-client works correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref.txt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* iterate

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-04-03 19:30:25 +00:00
Ruben Fiszel
ba214709b9 fix: add secretKeyRef support for jwt_secret and rsa_keys (#8698)
* feat: add secretKeyRef support for jwt_secret and extra fields (rsa_keys)

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

* chore: update ee-repo-ref.txt

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

* chore: update ee-repo-ref to 2c24cf597fdf8c4dccd483f1f1e5c49eb42ef3a3

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

Previous ee-repo-ref: ade3bb76f8e0a6e658313b54c7180577fc9efc37

New ee-repo-ref: 2c24cf597fdf8c4dccd483f1f1e5c49eb42ef3a3

Automated by sync-ee-ref workflow.

* test: replace unit tests with integration tests for jwt_secret and rsa_keys

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

* chore: update ee-repo-ref.txt

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-04-03 18:17:27 +00:00
hugocasa
bffa61e33f fix: dedicated worker dispatch, cross-workspace deps, UI improvements (#8689)
* feat: restore bun as default runtime for dedicated workers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: add context comment for bun dedicated worker nodejs migration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: dedicated worker dispatch for flows + add E2E tests

- Add workspace_id prefix to dedicated worker map lookup keys
- Update ee-repo-ref for dedicated worker path handling fix
- Add spawn_test_worker_dedicated/in_test_worker_dedicated test helpers
- Add 6 E2E tests for dedicated workers:
  - test_dedicated_flow_rawscript (regression for "Script not found" bug)
  - test_dedicated_flow_workspace_script
  - test_dedicated_flow_multiple_steps
  - test_dedicated_standalone_script
  - test_dedicated_runner_group
  - test_dedicated_flow_runners
- Add dedicated_flows.sql fixture with scripts, flows, and worker config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: always run dependency job for dedicated worker scripts

When a script with dedicated_worker=true is deployed with a pre-computed
lock (e.g. via wmill sync push), no dependency job was created, so the
dedicated worker never detected the update and kept running the old version.

Now dedicated worker scripts always generate a dependency job regardless
of whether a lock is provided. The dependency job runs on the dedicated
worker and triggers a restart so it picks up the new script version.

Fixes #8638

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use serial_test for dedicated worker tests to avoid WORKER_CONFIG races

Dedicated worker tests need non-default worker tags in the global
WORKER_CONFIG. When run in parallel (CI uses --test-threads=10),
multiple tests clobber each other's config. Use #[serial] to ensure
dedicated worker tests run sequentially.

Also load worker config from DB via load_worker_config() instead of
manually setting WORKER_CONFIG fields, ensuring consistency with the
monitor's reload path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: nodejs dedicated worker script_path shadowing + add multi-language E2E tests

Fix script_path shadowing in bun_executor nodejs branch where the wrapper
file path was passed to handle_dedicated_process instead of the logical
path, causing "Script not found" for all //nodejs dedicated workers.

Add E2E tests for dedicated flows in all supported languages:
- test_dedicated_flow_deno
- test_dedicated_flow_python
- test_dedicated_flow_bunnative (V8 PrewarmedIsolate path)
- test_dedicated_flow_bun_nodejs (//nodejs annotation)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: simplify dedicated worker dispatch + add serialization and E2E tests

- Unified lookup: always use {workspace}:{runnable_path} for dedicated
  worker dispatch, replacing the flow_step_id iteration approach
- Added serialization_semaphore parameter to executor start_worker fns
- Added E2E tests: cross-workspace isolation, conflicting flow step IDs,
  preprocessor on dedicated worker
- Added workspace field to RunJob for cross-workspace test support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: cross-workspace workspace dependencies on workers page

Add two new instance-level endpoints to the configs router:
- GET /configs/list_all_workspace_dependencies
- GET /configs/list_all_dedicated_with_deps

Both require devops role and return data across all workspaces,
enabling the workers page to show a consistent view of which
workspace dependencies exist regardless of which workspace the
user is browsing.

Update DedicatedWorkersSelector to use the new cross-workspace
endpoints with fallback to per-workspace calls for non-devops users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to include dedicated worker lookup simplification

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: use branch name for ee-repo-ref (CI can't fetch by SHA from non-default branch)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update ee-repo-ref.txt with new reference

* sqlx

* fix: revert serialization semaphore, multi-workspace picker, dep conflict warnings

- Remove serialization_semaphore from executor start_worker signatures
- Remove serialization test and fixtures
- Fix DedicatedWorkersSelector to preserve tags from other workspaces
  when toggling in the picker
- Track workspace deps per-workspace for conflict detection
- Show warning when dep exists in another workspace but not the script's
- Group runner groups per-workspace to prevent cross-workspace merging
- Add workspace to dep badge link URL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: simplify exec protocol — execd: for single-script, exec: for runner groups

Add execd:/execd_preprocess: commands to bun/deno/python wrappers for
single-script dedicated workers (no path needed). Runner groups keep
exec:/exec_preprocess: with path for multi-script disambiguation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add unit tests for execd:/exec: wrapper protocol

Verify generate_multi_script_wrapper produces both execd: (single-script)
and exec: (runner group) protocol handlers, including preprocessor variants.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update commit reference in ee-repo-ref.txt

* fix: remove beta badge from squash loop, keep tooltip

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update protocol tests to use execd: for single-script wrappers

Deno and bun single-script protocol tests now send execd:{args} instead
of exec:{path}:{args}, matching the updated wrapper protocol. Multi-script
(runner group) tests continue to use exec:{path}:{args}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove unused TEST_SCRIPT_PATH in deno protocol tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: review feedback — down migration, push_as workspace, UI improvements

- Use regexp_replace in down migration for positional accuracy
- Fix push_as() to use self.workspace_id instead of hardcoded value
- Remove per-workspace API fallbacks, use cross-workspace endpoints only
- Skip devops-only API calls when user is not devops (disabled prop)
- Fix duplicate key error for cross-workspace runner groups
- Add workspace to RunnerGroup for unique keying
- Reuse tagRow snippet for standalone items with expand/collapse
- Fix picker alignment: remove empty column for non-expandable items

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: comprehensive dedicated worker test coverage, fix Python execd_preprocess

- Add Python execd_preprocess: handler (was missing for single-script dedicated workers)
- Add 10 E2E tests: flow+standalone conflict, mixed lang fallback, unsupported lang
  flow runners, python runner group, bun/python/deno/bunnative preprocessors,
  runner group preprocessors, branchone flow
- Add 4 Python unit tests for execd:/execd_preprocess: protocol
- Update EE ref

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: review feedback — migration escaping, deno try/catch, loadRunnables guard

- Down migration: use E'...' so \n matches actual newlines
- Up migration: anchor regex with ^ to avoid mid-content matches
- Deno execd_preprocess: move JSON.parse inside try/catch
- DedicatedWorkersSelector: skip devops-only API calls when disabled

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add dedicated worker relative import tests for bun and python

Verifies that build_loader's CURRENT_PATH correctly resolves workspace-
relative imports when running on a dedicated worker subprocess.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: dedicated worker dispatch for nested flow structures (branches/loops)

- Add extract_flow_root() to strip nesting segments from runnable_path
- Dispatch uses flow_root/flow_step_id for nested paths, runnable_path
  for flat paths — deterministic, O(1)
- Fix assert_ran_on_dedicated_worker to BFS all descendants
- Fix python mode labels (python vs python3 for runner groups)
- Add tests: simple forloop, multi-step forloop, whileloop, branchall,
  nested branch-in-loop, mixed lang fallback, unsupported lang runners

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: fix ee-repo-ref SHA

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: hide picker and skip API calls for read-only users, hide empty runner badge

- Hide "Add more scripts/flows" section when disabled (read-only)
- Skip per-runnable API calls (getScriptByPath, getFlowByPath) for
  disabled users — just show path info
- Hide "0 runners" badge on flows with no eligible steps

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 9422b189762ae27edfc346541ae668a4ad728325

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

Previous ee-repo-ref: 4c6ba214bfc23fff05d1dc3200ac59e650af3f4f

New ee-repo-ref: 9422b189762ae27edfc346541ae668a4ad728325

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-04-03 17:50:07 +00:00
Ruben Fiszel
27ca417201 fix: resolve schedule update deadlock (#8701)
* feat: add --main flag to write_latest_ee_ref.sh to point to latest EE main

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve schedule update deadlock by fixing lock ordering in edit_schedule

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 17:44:10 +00:00
Ruben Fiszel
c4c9ef5fd7 feat: add optional labels to scripts, flows, apps, schedules, triggers (#8609)
* feat: add optional labels to scripts, flows, apps, raw apps, schedules, and triggers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update sqlx cache, make labels optional in openapi, regenerate system prompts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add minimal labels input UI to script, flow, and schedule editors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: reduce gap between summary and labels input

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add labels to script/flow detail pages and summary/path popover

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: move labels inside SummaryPathDisplay trigger for clickable area, reduce gap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: display labels inline to the right of summary, not below

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: increase gap between summary and labels

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add labels to resources/variables, make labels nullable, add home page label filter badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add labels to workspace export/import, resources, variables + test coverage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: make migration idempotent, regenerate sqlx cache after merge

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: pass labels in script create and flow create/update API calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add labels input UI to resource and variable editors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove negative margin from LabelsInput to prevent overlap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add top and left margin to LabelsInput for better spacing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: reduce left margin on LabelsInput

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: widen label input to w-32

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use inline-flex so LabelsInput doesn't stretch full width

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove flex-wrap so label input stays on same line as badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add label filter presets to resources, variables, and schedules search

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use max-w-32 on label input to prevent stretching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: pull labels closer to summary with negative top margin

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: increase negative margin to pull labels even closer to summary

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: pass labels in schedule create/update API calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use COALESCE to preserve existing labels when not provided in schedule/flow update

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add labels to CreateResource, EditResource, CreateVariable, EditVariable in OpenAPI spec

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: display label badges on resource and variable list pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: display label badges on schedule and all trigger list pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add folder and label presets to schedules search filter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: apply user_folders_only filter on all workspaces including admins

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add label presets to resources and variables search filters

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: derive folder presets from loaded items, not all workspace folders

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add label query parameter to resource and variable list endpoints in OpenAPI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: display label filter badges inline with folder filters on home page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert "feat: display label filter badges inline with folder filters on home page"

This reverts commit 6767a50aa6.

* feat: support comma-separated label filters (allowMultiple) in all list endpoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: append label presets with comma for allowMultiple filters instead of duplicating key

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: hide label presets that are already in the comma-separated filter value

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace unsafe manual SQL ARRAY construction with parameterized queries, add labels to ScriptWDraft

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: complete down migration, add labels to Resource/Variable OpenAPI schemas, remove type cast, add label length validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add labels field to Schedule test fixture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add labels field to Rust client struct constructions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: regenerate sqlx cache with --all-features for EE builds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: regenerate sqlx cache and package-lock after merge with main

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: squash two migrations into one, use IF NOT EXISTS for idempotency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: track label changes in SummaryPathDisplay to enable save button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use JSON string comparison for label dirty tracking in popover

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: navigate to script by path after save from popover to load new version

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update initialLabels after save so subsequent label changes enable save again

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use onchange callback for label dirty tracking instead of derived comparison

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: reload script by path after label save to fetch new version

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: propagate script/flow labels to jobs at push time

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: show script/flow labels on runs page, merge with wm_labels for completed jobs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: change job labels type from JSONB to text[], show labels on job detail page, fix type mismatch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add labels to QueuedJob struct, fix get_job queries to return v2_job.labels

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace +Label text with icon only

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add tag icon before labels on job detail page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: move tag icon inside badge on job detail page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use blue badge with tag icon in RunBadges, remove duplicate labels from JobDetailHeader

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: set icon position to left so tag icon renders in badge

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: render Tag icon inline in badge children instead of via icon prop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: retry icon prop with small badge and position left

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add hover tooltip showing "Label: X" on job label badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: include v2_job.labels in runs page label filter and broad search

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: regenerate sqlx cache and system prompts after merge with main

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add labels to EE JobPayload constructions, regenerate sqlx cache with --all-features

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: regenerate sqlx cache CE-only (without EE symlinks that cause conflicts)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update remaining wm_labels JSONB queries to use text[] merge expression

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: simplify job labels to just read v2_job.labels (wm_labels already merged at completion)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: consistent label badge spacing with gap-0.5 wrapper and px-0.5 on badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add labels: None to test utils JobPayload construction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add labels to all test fixture JobPayload/NewFlow/EditApp constructions, regenerate sqlx cache

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: fix vertical content shift by fixing container and input height to h-5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: npm_check errors - unused imports, combinedItems order, flow.labels type, badge px-1 padding

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove unused FolderService imports, fix label badge alignment in RunBadges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: restore deleted service imports in variables page, remove empty loadFolders

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: trigger CI with updated ee-repo-ref

* chore: update ee-repo-ref to merged EE companion PR

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: trigger fresh CI run for updated ee-repo-ref

* fix: match label badge size with other badges in RunBadges using {large} prop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove icon from RunBadges label badge to fix vertical alignment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: shorten "Job kind" to "Kind" in run badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add small inline tag icon (10px, -mt-px) to label badge without disrupting height

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add "Label: X" hover tooltip to all label badges, show hidden labels on +N hover

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add tag icon and "Label: X" tooltip to home page label filter badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: show LabelsInput even when path is hidden in ResourceEditor

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add labels input to new resource creation drawer (AppConnectInner)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* iterate

* fix: add LabelsInput to all resource creation steps in AppConnectInner

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: reduce LabelsInput top margin from -mt-3 to -mt-1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: increase negative margin to -mt-2 for tighter spacing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: split the difference with -mt-1.5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: adjust to -mt-1 for label spacing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: per-site label spacing via class prop instead of global negative margin

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: make label badges clickable to toggle label filter on resources, variables, schedules

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use proper array indexOf for label filter toggle, set undefined correctly on removal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use delete instead of undefined to properly clear label filter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add /labels/list endpoint and autocomplete dropdown to LabelsInput

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use inline preventDefault for Svelte 5 event handling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add "Create new" option in label autocomplete, regenerate sqlx cache with update_sqlx.sh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add GIN indexes on labels column for all 16 tables

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove CONCURRENTLY from GIN index creation in migration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add comprehensive label coverage for pull, edit, removal across all item types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: simplify job label filters to only use v2_job.labels, remove wm_labels back-compat

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add integration tests for job label propagation, display, and filtering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review findings — missing labels in fetch_script_for_update, app rename, escape key bug

- Add `labels` to SELECT in `fetch_script_for_update` to prevent lost labels on script clone
- Pass `labels` in app branch of `moveRenameManager.ts` so app renames preserve labels
- Clear `inputValue` before `adding = false` in LabelsInput escape handler to prevent accidental label add via onblur
- Fix `test_job_label_filter` to complete jobs via SQL (label filtering only works on completed jobs)
- Add `test_wm_labels_from_result_merged_with_static_labels` integration test using Bun

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 17:39:32 +00:00
centdix
b960598431 fix: hide deprecated cli metadata commands (#8699)
* fix: hide deprecated cli metadata commands

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

* fix: simplify generate-metadata guidance

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-03 15:38:01 +00:00
centdix
f234df97ec fix: support raw app deployment history (#8657)
* fix: support raw app deployment history

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

* fix: refresh deployment history diffs

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

* fix: preserve deployment history preview context

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

* fix: limit deployment history to diffs

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

* chore: remove unused history backend hook

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-03 14:56:56 +00:00
Diego Imbert
a3073ad824 fix: debounce S3 proxy logs (#8694)
* Debounce S3 proxy logs

* missing workspace id

* nit perf

* nit

* prevent DOS

* handle 4xx/5xx statuses

* fix magic numbers
2026-04-03 13:46:09 +00:00
Alexander Petric
ceaa613522 chore: add .playwright-mcp/ to .gitignore (#8696)
Prevent Playwright MCP console logs from being accidentally committed.
Addresses GitHub security advisory for leaked credentials in log files.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:39:10 +00:00
Ruben Fiszel
0317d5891c feat: add powershell common parameters support (#8683)
* feat: add powershell common parameters support (-Verbose, -Debug, -ErrorAction, -WhatIf)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add powershell common params to script editor test panel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: detect CmdletBinding from code instead of schema in script editor

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: ignore commented-out CmdletBinding in powershell detection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use preference variables for -Verbose/-Debug instead of CLI args

Verbose/Debug output goes to PowerShell stream 4/5 which isn't captured
by the 2>&1 redirect. Setting $VerbosePreference/$DebugPreference in the
wrapper scope propagates to child scripts and output flows through the
host to stderr, which Windmill captures as logs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use *>&1 to capture all powershell streams including verbose/debug

The previous 2>&1 only captured error stream. Verbose (stream 4) and
debug (stream 5) output was silently lost. Using *>&1 redirects all
streams to success stream so they flow through Tee-Object into logs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use targeted stream redirects (4>&1 5>&1 2>&1) instead of *>&1

*>&1 breaks $PSCmdlet.ShouldProcess() by redirecting internal streams.
Only redirect verbose (4), debug (5), and error (2) to success stream.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: revert to 2>&1 redirect — stream 4/5 redirects break powershell

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use 4>&1 5>&1 for verbose/debug capture, remove WhatIf support

Stream 4/5 redirects capture verbose/debug in the pipeline. WhatIf is
removed because $PSCmdlet.ShouldProcess() doesn't work when scripts
are invoked through Windmill's wrapper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: redirect verbose/debug to files to keep result pipeline clean

Verbose (4) and debug (5) streams are redirected to separate log files
during script execution, then output via Write-Host after the script
completes. This keeps them out of the Tee-Object pipeline (used for
result extraction) while still showing them in the job logs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: output verbose/debug to stderr via Console.Error for log capture

Write-Host goes to stdout which gets mixed with result output and
truncated by OSS log threshold. Using [Console]::Error.WriteLine()
writes to stderr which Windmill captures separately as logs, with
VERBOSE:/DEBUG: prefixes for clarity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: redirect script output to file only, send verbose/debug to stdout

The OSS log storage has a 9KB threshold. Previously, Tee-Object sent
the full JSON result to both stdout (logs) and the pipe file, eating
the log budget. Now script output goes only to the pipe file (> $pipe),
and only verbose/debug messages go to stdout for the log viewer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: preserve original Tee-Object behavior, append verbose/debug after

Keep the original wrapper behavior (Tee-Object to stdout + pipe file).
Only add 4>verbose.log 5>debug.log to capture those streams, and
output them at the end of logs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: inject preference vars into main.ps1 instead of CLI args

Passing -Verbose/-Debug as CLI args causes PowerShell module loading
to emit verbose noise. Instead, inject $VerbosePreference/$DebugPreference
inside main.ps1's try block so they only affect user code. Stream 4/5
are still redirected to files in the wrapper for log output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: restore common param toggles from previous job args on Run Again

Extract _wm_ps_* keys from loaded args and initialize the toggle
states in PowerShellCommonParams. Also strip them from main args
so they don't appear as unknown schema form inputs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: show active common param badges when section is collapsed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: inject ErrorAction as preference variable instead of CLI arg

-ErrorAction as a CLI arg only affects the caller, not the script's
internal error handling. Setting $ErrorActionPreference inside main.ps1
correctly overrides the default 'Stop' behavior for the user's code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: ensure full backward compatibility with existing powershell scripts

- Only filter common param names when [CmdletBinding()] is present
  (without it, $Verbose etc. are regular user-defined parameters)
- Only add 4>verbose.log 5>debug.log and log output lines when common
  params are actually enabled — original wrapper is unchanged otherwise

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: lighter styling for common params section

Replaced heavy Section component with a subtle inline chevron toggle
labeled "Common parameters". Smaller text, secondary color, indented
options. Badges still show when collapsed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: rename section to CmdletBinding parameters

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add ..Default::default() to windmill-parser-r (new parser from main)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: missing comma in graphql parser test + merge main

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add missing commas before ..Default::default() in parser tests

Merge from main brought test constructors with formatting issues
from the original automated script (missing comma between last field
and ..Default::default()).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: restore comment markers in nu parser test that script broke

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review — ignore commented CmdletBinding, clear stale params

1. Parser: strip comment lines before detecting [CmdletBinding()] to
   avoid false positives from commented-out attributes
2. RunForm: always assign psCommonParams (not just when non-empty) so
   stale settings from a previous run don't leak into later runs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:03:22 +00:00
Ruben Fiszel
7485a5db04 remove dead legacyBehaviour param from metadata functions (#8695)
The legacyBehaviour parameter on generateFlowLockInternal,
generateAppLocksInternal, and generateScriptMetadataInternal was never
passed as true — the tree parameter alone determines the code path.
Replace `!legacyBehaviour && tree` with just `tree` and remove the
param from all call sites. getRawWorkspaceDependencies keeps its
legacyBehaviour param since it has a real effect there.

Also adds 6 integration tests covering generate-metadata lockfile
generation and idempotency for scripts, flows, and apps.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:01:34 +00:00
Diego Imbert
0cfa462c37 fix: optimize S3 proxy performance (#8685)
* perf: re-export GetOptions and GetRange from object_store

Needed by S3 proxy to use get_opts with range for single-request
range fetches instead of HEAD + get_range.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Avoid logging S3 proxy requests as info

* Revert "Avoid logging S3 proxy requests as info"

This reverts commit b6359a7a03.

* Don't log s3 proxy

* Revert "Don't log s3 proxy"

This reverts commit 2b21ee3c78.

* Update duckdb

* AUTOMATIC_MIGRATION for ducklake

* ee repo ref

* wrong comment

* chore: update ee-repo-ref to 41b0d1cb312919109407640fc4bd7060cfe0e107

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

Previous ee-repo-ref: 9b97a1c563365006657c4c6cde6e7df31c5173c3

New ee-repo-ref: 41b0d1cb312919109407640fc4bd7060cfe0e107

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-04-03 11:53:10 +00:00
Kain
6656b46f10 fix: align script push metadata warning with generated locks (#8690) 2026-04-03 11:41:31 +00:00
Alexander Petric
5b7fa63bf1 feat: add application-level heartbeat support for websocket triggers (#8686)
* feat: add application-level heartbeat support for websocket triggers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update SQLx metadata

* chore: regenerate auto-generated schema and skill files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: handle missing heartbeat channel gracefully, fix TextInput props

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: only clone heartbeat sender when heartbeat is configured

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-04-03 11:31:08 +00:00
hugocasa
cdf3c29664 fix: use pre-aggregated stats for telemetry job usage queries (#8688)
* fix: use pre-aggregated worker_group_job_stats for telemetry job usage queries

Replace slow v2_job_completed JOIN v2_job scans with reads from the
pre-aggregated worker_group_job_stats table for the schedule-only
job_usage (48h) and daily_job_usage queries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to telemetry-query-timeout branch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 94567b204a5536ec3dc7591830c58c5bdc1d8381

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

Previous ee-repo-ref: da62a74e965a079d95eea6510f2ac7fc004cdccc

New ee-repo-ref: 94567b204a5536ec3dc7591830c58c5bdc1d8381

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-04-03 11:30:33 +00:00
Ruben Fiszel
81ab777cbb chore(main): release 1.673.0 (#8660)
* chore(main): release 1.673.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-04-02 19:41:12 -04:00
hugocasa
61a867f086 Revert "feat: restore bun for dedicated workers, fix dispatch & serialization, cross-workspace deps (#8645)" (#8687)
This reverts commit 619ebb65ce.
2026-04-02 23:09:38 +00:00
Diego Imbert
8581a3300d fix: Run typed pg queries in a single protocol conversation (#8679)
* Run typed pg queries in one protocol conversation

* Update pg queries for db manager to use explicit type syntax

* Unused import
2026-04-02 22:00:38 +00:00
Ruben Fiszel
ff5fa9f64f fix: poll for preview results to avoid undici headers timeout (#8682)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 20:55:46 +00:00
Ruben Fiszel
55e8a5cff1 fix: add HMAC signature verification to Slack interactive callback endpoint (#8611)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 20:55:23 +00:00
Ruben Fiszel
1a39bd538d add opt-in SMTP click tracking disable for email links (#8665)
* feat: add opt-in SMTP click tracking disable for email links

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref.txt for email clicktracking branch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref.txt after simplification

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: exclude trailing commas from URL regex in clicktracking

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 57dd88faa3b0b354f813385cf3f6a34eca54a4a1

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

Previous ee-repo-ref: 5cf901db7fb0ea169b09564372e444f28e23ac3a

New ee-repo-ref: 57dd88faa3b0b354f813385cf3f6a34eca54a4a1

Automated by sync-ee-ref workflow.

* chore: update ee-repo-ref.txt to include dedicated worker fixes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-04-02 20:44:08 +00:00
Ruben Fiszel
1049c1026b fix Windows compilation errors in MemoryLimitedChild (#8684)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 20:33:23 +00:00
hugocasa
619ebb65ce feat: restore bun for dedicated workers, fix dispatch & serialization, cross-workspace deps (#8645)
* feat: restore bun as default runtime for dedicated workers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: add context comment for bun dedicated worker nodejs migration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: dedicated worker dispatch for flows + add E2E tests

- Add workspace_id prefix to dedicated worker map lookup keys
- Update ee-repo-ref for dedicated worker path handling fix
- Add spawn_test_worker_dedicated/in_test_worker_dedicated test helpers
- Add 6 E2E tests for dedicated workers:
  - test_dedicated_flow_rawscript (regression for "Script not found" bug)
  - test_dedicated_flow_workspace_script
  - test_dedicated_flow_multiple_steps
  - test_dedicated_standalone_script
  - test_dedicated_runner_group
  - test_dedicated_flow_runners
- Add dedicated_flows.sql fixture with scripts, flows, and worker config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: always run dependency job for dedicated worker scripts

When a script with dedicated_worker=true is deployed with a pre-computed
lock (e.g. via wmill sync push), no dependency job was created, so the
dedicated worker never detected the update and kept running the old version.

Now dedicated worker scripts always generate a dependency job regardless
of whether a lock is provided. The dependency job runs on the dedicated
worker and triggers a restart so it picks up the new script version.

Fixes #8638

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use serial_test for dedicated worker tests to avoid WORKER_CONFIG races

Dedicated worker tests need non-default worker tags in the global
WORKER_CONFIG. When run in parallel (CI uses --test-threads=10),
multiple tests clobber each other's config. Use #[serial] to ensure
dedicated worker tests run sequentially.

Also load worker config from DB via load_worker_config() instead of
manually setting WORKER_CONFIG fields, ensuring consistency with the
monitor's reload path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: nodejs dedicated worker script_path shadowing + add multi-language E2E tests

Fix script_path shadowing in bun_executor nodejs branch where the wrapper
file path was passed to handle_dedicated_process instead of the logical
path, causing "Script not found" for all //nodejs dedicated workers.

Add E2E tests for dedicated flows in all supported languages:
- test_dedicated_flow_deno
- test_dedicated_flow_python
- test_dedicated_flow_bunnative (V8 PrewarmedIsolate path)
- test_dedicated_flow_bun_nodejs (//nodejs annotation)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: simplify dedicated worker dispatch + add serialization and E2E tests

- Unified lookup: always use {workspace}:{runnable_path} for dedicated
  worker dispatch, replacing the flow_step_id iteration approach
- Added serialization_semaphore parameter to executor start_worker fns
- Added E2E tests: cross-workspace isolation, conflicting flow step IDs,
  preprocessor on dedicated worker
- Added workspace field to RunJob for cross-workspace test support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: cross-workspace workspace dependencies on workers page

Add two new instance-level endpoints to the configs router:
- GET /configs/list_all_workspace_dependencies
- GET /configs/list_all_dedicated_with_deps

Both require devops role and return data across all workspaces,
enabling the workers page to show a consistent view of which
workspace dependencies exist regardless of which workspace the
user is browsing.

Update DedicatedWorkersSelector to use the new cross-workspace
endpoints with fallback to per-workspace calls for non-devops users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to include dedicated worker lookup simplification

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: use branch name for ee-repo-ref (CI can't fetch by SHA from non-default branch)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update ee-repo-ref.txt with new reference

* sqlx

* fix: revert serialization semaphore, multi-workspace picker, dep conflict warnings

- Remove serialization_semaphore from executor start_worker signatures
- Remove serialization test and fixtures
- Fix DedicatedWorkersSelector to preserve tags from other workspaces
  when toggling in the picker
- Track workspace deps per-workspace for conflict detection
- Show warning when dep exists in another workspace but not the script's
- Group runner groups per-workspace to prevent cross-workspace merging
- Add workspace to dep badge link URL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: simplify exec protocol — execd: for single-script, exec: for runner groups

Add execd:/execd_preprocess: commands to bun/deno/python wrappers for
single-script dedicated workers (no path needed). Runner groups keep
exec:/exec_preprocess: with path for multi-script disambiguation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add unit tests for execd:/exec: wrapper protocol

Verify generate_multi_script_wrapper produces both execd: (single-script)
and exec: (runner group) protocol handlers, including preprocessor variants.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update commit reference in ee-repo-ref.txt

* fix: remove beta badge from squash loop, keep tooltip

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update protocol tests to use execd: for single-script wrappers

Deno and bun single-script protocol tests now send execd:{args} instead
of exec:{path}:{args}, matching the updated wrapper protocol. Multi-script
(runner group) tests continue to use exec:{path}:{args}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove unused TEST_SCRIPT_PATH in deno protocol tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:37:02 +00:00
Ruben Fiszel
d2d6810db9 feat: add LIMIT_WINDOWS_TO_1CU env var for Windows worker memory limits (#8681)
* feat: add LIMIT_WINDOWS_TO_1CU env var for Windows worker memory limits

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address CI review — stricter env var parsing and SAFETY comment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:31:07 +00:00
Ruben Fiszel
39af1b75af fix: skip generate-metadata confirmation prompt in non-interactive CI (#8678)
* fix: generate-metadata non-interactive CI and misleading log path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add hash consistency tests for workspace deps staleness checks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:28:39 +00:00
Ruben Fiszel
d569e9e29c fix: resolve race condition where flow sync push reverts to stale version (#8673)
* fix: resolve race condition where flow sync push reverts to stale version

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: add sqlx offline cache for new queries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add version guard before writing to prevent TOCTOU race

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:17:37 +00:00
Ruben Fiszel
381011a4a8 fix: pass selected language to AI agent when generating flow scripts (#8680)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:06:22 +00:00
hugocasa
f0437eba19 feat: add endpoint to restart workers in a worker group (#8659)
* feat: add endpoint to restart workers in a worker group

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: regenerate sqlx query cache

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add missing modules field to RawCode in tests and regenerate sqlx cache

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* update sqlx

* fix: use require_devops_role for restart worker group endpoint

Matches the permission level of the clean cache endpoint (update_config),
allowing both superadmin and devops role users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address review feedback for restart worker group

- Fix OpenAPI description to say "devops role" instead of "superadmin"
- Add dispatch('reload') after restart to refresh worker list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: only dispatch reload on successful restart

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:36:48 +00:00
Ruben Fiszel
d8edaad99c improve bun bundle error message for syntax errors (#8677)
* fix: improve bun bundle error message for syntax errors like unclosed brackets

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* revert: remove error hint from node_builder.ts wrapper catch blocks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:19:46 +00:00
Ruben Fiszel
7fd0bf974d fix: respect disabled fields in JSON input mode (#8663)
* fix: respect disabled fields in JSON input mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: guard against undefined default in disabled field enforcement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: show toast when disabled fields are reset to defaults on run

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:13:12 +00:00
hugocasa
6a5cfbc159 feat: add Entra ID (Azure Workload Identity) database auth (#8526)
* feat: add Entra ID (Azure Workload Identity) support for database auth

Add support for Azure Workload Identity to authenticate to Azure Database
for PostgreSQL using short-lived Entra ID tokens. Mirrors the existing
AWS IAM RDS auth pattern.

- Extract shared DatabaseParams to db_params.rs for reuse across providers
- Add DatabaseUrl::EntraId variant with token refresh
- Detect "entraid" magic password in DATABASE_URL
- Unified background refresh task for both IAM RDS and Entra ID
- Support sovereign clouds via AZURE_AUTHORITY_HOST env var

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: restore needs_refresh() check in background token refresh task

The unified refresh task was missing the needs_refresh() gate, causing
it to refresh tokens every 10 seconds instead of only when near expiry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref.txt for Entra ID branch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: move entraid env var reads inside cfg(private) block

Fixes unused variable warnings in OSS and EE-without-private builds
where -D warnings is enabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 0e001bab643e449b3310b0692dd3598ee0902ecc

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

Previous ee-repo-ref: 44199013ed0c96680672e718f35124aa34a5d010

New ee-repo-ref: 0e001bab643e449b3310b0692dd3598ee0902ecc

Automated by sync-ee-ref workflow.

* refactor: add needs_refresh() and refresh_if_needed() to DatabaseUrl

Simplify duplicated refresh logic per Claude review suggestion.
Background task and get_database_url() now use shared methods
instead of matching on each variant individually.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-04-02 16:00:33 +02:00
Ruben Fiszel
8c3c97f7a6 fix: sanitize MCP tool schemas for JSON Schema draft 2020-12 compliance (#8666)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-02 13:53:16 +00:00
280 changed files with 9194 additions and 1512 deletions

1
.gitignore vendored
View File

@@ -29,3 +29,4 @@ frontend/.svelte-kit
backend/chrome_profiler.json
.fast-check/
__pycache__/
.playwright-mcp/

View File

@@ -1,5 +1,32 @@
# Changelog
## [1.673.0](https://github.com/windmill-labs/windmill/compare/v1.672.0...v1.673.0) (2026-04-02)
### Features
* add endpoint to restart workers in a worker group ([#8659](https://github.com/windmill-labs/windmill/issues/8659)) ([f0437eb](https://github.com/windmill-labs/windmill/commit/f0437eba1925a9aa4c430008027d637a0c89ee39))
* add Entra ID (Azure Workload Identity) database auth ([#8526](https://github.com/windmill-labs/windmill/issues/8526)) ([6a5cfbc](https://github.com/windmill-labs/windmill/commit/6a5cfbc159a0ad7925fd7ce5eefc8eaa21bbb70b))
* add LIMIT_WINDOWS_TO_1CU env var for Windows worker memory limits ([#8681](https://github.com/windmill-labs/windmill/issues/8681)) ([d2d6810](https://github.com/windmill-labs/windmill/commit/d2d6810db954114f3333853bd3476cb8fc735f92))
* restore bun for dedicated workers, fix dispatch & serialization, cross-workspace deps ([#8645](https://github.com/windmill-labs/windmill/issues/8645)) ([619ebb6](https://github.com/windmill-labs/windmill/commit/619ebb65ce8dce8264add31c3147919802a8286a))
### Bug Fixes
* add HMAC signature verification to Slack interactive callback endpoint ([#8611](https://github.com/windmill-labs/windmill/issues/8611)) ([55e8a5c](https://github.com/windmill-labs/windmill/commit/55e8a5cff1f185b1dbd332d37b877972efa1ed7d))
* correct raw app flow inputs ([#8667](https://github.com/windmill-labs/windmill/issues/8667)) ([28c0730](https://github.com/windmill-labs/windmill/commit/28c073056c65d4ed1600e39679497e5af964347f))
* pass selected language to AI agent when generating flow scripts ([#8680](https://github.com/windmill-labs/windmill/issues/8680)) ([381011a](https://github.com/windmill-labs/windmill/commit/381011a4a8e48454e9c146c64db502293e646b99))
* poll for preview results to avoid undici headers timeout ([#8682](https://github.com/windmill-labs/windmill/issues/8682)) ([ff5fa9f](https://github.com/windmill-labs/windmill/commit/ff5fa9f64fe4aaf33e06b20f02373894b5df0f95))
* pre-fix trigger edited_by for superadmins not in workspace ([#8669](https://github.com/windmill-labs/windmill/issues/8669)) ([350ffdc](https://github.com/windmill-labs/windmill/commit/350ffdce297ba5b84f9dd247eede6da0c6b0956c))
* resolve race condition where flow sync push reverts to stale version ([#8673](https://github.com/windmill-labs/windmill/issues/8673)) ([d569e9e](https://github.com/windmill-labs/windmill/commit/d569e9e29c588243a90b1cd25f866efb0d178640))
* respect disabled fields in JSON input mode ([#8663](https://github.com/windmill-labs/windmill/issues/8663)) ([7fd0bf9](https://github.com/windmill-labs/windmill/commit/7fd0bf974d2ba2644bb01dd5e9ddc84749e166f5))
* Run typed pg queries in a single protocol conversation ([#8679](https://github.com/windmill-labs/windmill/issues/8679)) ([8581a33](https://github.com/windmill-labs/windmill/commit/8581a3300d056040b7e3ab77d629c74f034c9c97))
* sanitize MCP tool schemas for JSON Schema draft 2020-12 compliance ([#8666](https://github.com/windmill-labs/windmill/issues/8666)) ([8c3c97f](https://github.com/windmill-labs/windmill/commit/8c3c97f7a670d47019cc666219f8187f48499672))
* skip generate-metadata confirmation prompt in non-interactive CI ([#8678](https://github.com/windmill-labs/windmill/issues/8678)) ([39af1b7](https://github.com/windmill-labs/windmill/commit/39af1b75afc8458f85dec4fe51dfaed3d0cb000d))
* strip f/ prefix from folder paths when deploying from workspace forks ([#8662](https://github.com/windmill-labs/windmill/issues/8662)) ([7ab0ea5](https://github.com/windmill-labs/windmill/commit/7ab0ea581d349fbfdb56d22cf9903a90efa045bb))
* support branch-specific folder.meta.yaml in missing-meta check ([#8661](https://github.com/windmill-labs/windmill/issues/8661)) ([c87a6a0](https://github.com/windmill-labs/windmill/commit/c87a6a0f2c1346bf5e21f128d32d89bdca039243))
* validate rd redirect on login with same rules as logout ([#8655](https://github.com/windmill-labs/windmill/issues/8655)) ([bcce627](https://github.com/windmill-labs/windmill/commit/bcce62738791a4e9b9f4dbc64731eef163230172))
## [1.672.0](https://github.com/windmill-labs/windmill/compare/v1.671.0...v1.672.0) (2026-04-01)

View File

@@ -26,6 +26,7 @@ Open-source platform for internal tools, workflows, API integrations, background
- **DB**: `psql postgres://postgres:changeme@localhost:5432/windmill`
- **Login**: `admin@windmill.dev` / `changeme`
- **Instance settings**: navigate to `/#superadmin-settings`
- **Migrations**: use `cargo sqlx migrate add -r <name>` from `backend/` to create new migrations (never generate timestamps manually)
## Banned Patterns

View File

@@ -34,7 +34,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO websocket_trigger (\n workspace_id,\n path,\n url,\n script_path,\n is_flow,\n mode,\n filters,\n filter_logic,\n initial_messages,\n url_runnable_args,\n edited_by,\n can_return_message,\n can_return_error_result,\n permissioned_as,\n edited_at,\n error_handler_path,\n error_handler_args,\n retry\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, now(), $15, $16, $17\n )\n ",
"query": "\n INSERT INTO websocket_trigger (\n workspace_id,\n path,\n url,\n script_path,\n is_flow,\n mode,\n filters,\n filter_logic,\n initial_messages,\n url_runnable_args,\n edited_by,\n can_return_message,\n can_return_error_result,\n permissioned_as,\n edited_at,\n error_handler_path,\n error_handler_args,\n retry,\n heartbeat\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, now(), $15, $16, $17, $18\n )\n ",
"describe": {
"columns": [],
"parameters": {
@@ -32,10 +32,11 @@
"Varchar",
"Varchar",
"Jsonb",
"Jsonb",
"Jsonb"
]
},
"nullable": []
},
"hash": "6948eb5aabf82f2f4a08dd4410eb472080ecab3ed652912397245e5216ae0389"
"hash": "11fd92de8688ef6b4d524aade507850a9cb3e097f2d957219d04ad134a5e0399"
}

View File

@@ -43,7 +43,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO schedule (\n workspace_id, path, schedule, timezone, edited_by, script_path,\n is_flow, args, enabled, email, permissioned_as,\n on_failure, on_failure_times, on_failure_exact, on_failure_extra_args,\n on_recovery, on_recovery_times, on_recovery_extra_args,\n on_success, on_success_extra_args,\n ws_error_handler_muted, retry, summary, no_flow_overlap,\n tag, paused_until, cron_version, description, dynamic_skip\n ) VALUES (\n $1, $2, $3, $4, $5, $6,\n $7, $8, $9, $10, $11,\n $12, $13, $14, $15,\n $16, $17, $18,\n $19, $20,\n $21, $22, $23, $24,\n $25, $26, $27, $28, $29\n )\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip\n ",
"query": "\n INSERT INTO schedule (\n workspace_id, path, schedule, timezone, edited_by, script_path,\n is_flow, args, enabled, email, permissioned_as,\n on_failure, on_failure_times, on_failure_exact, on_failure_extra_args,\n on_recovery, on_recovery_times, on_recovery_extra_args,\n on_success, on_success_extra_args,\n ws_error_handler_muted, retry, summary, no_flow_overlap,\n tag, paused_until, cron_version, description, dynamic_skip, labels\n ) VALUES (\n $1, $2, $3, $4, $5, $6,\n $7, $8, $9, $10, $11,\n $12, $13, $14, $15,\n $16, $17, $18,\n $19, $20,\n $21, $22, $23, $24,\n $25, $26, $27, $28, $29, $30\n )\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip,\n labels\n ",
"describe": {
"columns": [
{
@@ -162,6 +162,11 @@
"ordinal": 31,
"name": "dynamic_skip",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -194,7 +199,8 @@
"Timestamptz",
"Text",
"Text",
"Varchar"
"Varchar",
"TextArray"
]
},
"nullable": [
@@ -229,8 +235,9 @@
true,
true,
true,
true,
true
]
},
"hash": "dd20f94d560238096390371c98ded1f80825a11cd61c0bb431678ad9ab4a138e"
"hash": "2effe885aafaa0c5fc1f969b8c6ffbd38c53fb586251ba780b75a007e5a47ed6"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow SET versions = array_append(versions, $1) WHERE path = $2 AND workspace_id = $3 AND (versions[array_upper(versions, 1)] IS DISTINCT FROM $1)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "32f26d69b15a74fc96dd585f9eb3c998447ca8b97894bb1a2b238f984c1dc588"
}

View File

@@ -1,19 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO resource\n (workspace_id, path, value, description, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, $6, now()) ON CONFLICT (workspace_id, path)\n DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now()",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Jsonb",
"Text",
"Varchar",
"Varchar"
]
},
"nullable": []
},
"hash": "39426bd3018b390ea2073419884cf6cb506c75e84c65438c9026831eb10d340b"
}

View File

@@ -45,31 +45,36 @@
},
{
"ordinal": 8,
"name": "labels",
"type_info": "TextArray"
},
{
"ordinal": 9,
"name": "is_expired",
"type_info": "Bool"
},
{
"ordinal": 9,
"ordinal": 10,
"name": "is_refreshed",
"type_info": "Bool"
},
{
"ordinal": 10,
"ordinal": 11,
"name": "refresh_error",
"type_info": "Text"
},
{
"ordinal": 11,
"ordinal": 12,
"name": "is_linked",
"type_info": "Bool"
},
{
"ordinal": 12,
"ordinal": 13,
"name": "is_oauth?",
"type_info": "Bool"
},
{
"ordinal": 13,
"ordinal": 14,
"name": "account",
"type_info": "Int4"
}
@@ -89,6 +94,7 @@
false,
true,
true,
true,
null,
null,
true,

View File

@@ -42,6 +42,11 @@
"ordinal": 7,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -57,6 +62,7 @@
false,
false,
true,
true,
true
]
},

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, description, account, is_oauth, expires_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, description, account, is_oauth, expires_at, labels)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
"describe": {
"columns": [],
"parameters": {
@@ -12,10 +12,11 @@
"Varchar",
"Int4",
"Bool",
"Timestamptz"
"Timestamptz",
"TextArray"
]
},
"nullable": []
},
"hash": "2be66f23536223549db9b50025932b6b1bad90b8fa47d97acb7d75aa3c37ef86"
"hash": "48efd8f89df9c1dd8f8a4eb2b2640fcb380f2470c8488371b207a42cb7d4cd26"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n websocket_trigger\n SET\n url = $1,\n script_path = $2,\n path = $3,\n is_flow = $4,\n filters = $5,\n filter_logic = $6,\n initial_messages = $7,\n url_runnable_args = $8,\n edited_by = $9,\n permissioned_as = $10,\n can_return_message = $11,\n can_return_error_result = $12,\n edited_at = now(),\n server_id = NULL,\n error = NULL,\n error_handler_path = $15,\n error_handler_args = $16,\n retry = $17\n WHERE\n workspace_id = $13 AND path = $14\n ",
"query": "\n UPDATE\n websocket_trigger\n SET\n url = $1,\n script_path = $2,\n path = $3,\n is_flow = $4,\n filters = $5,\n filter_logic = $6,\n initial_messages = $7,\n url_runnable_args = $8,\n edited_by = $9,\n permissioned_as = $10,\n can_return_message = $11,\n can_return_error_result = $12,\n edited_at = now(),\n server_id = NULL,\n error = NULL,\n error_handler_path = $15,\n error_handler_args = $16,\n retry = $17,\n heartbeat = $18\n WHERE\n workspace_id = $13 AND path = $14\n ",
"describe": {
"columns": [],
"parameters": {
@@ -21,10 +21,11 @@
"Text",
"Varchar",
"Jsonb",
"Jsonb",
"Jsonb"
]
},
"nullable": []
},
"hash": "e3d4f89ce36337af15d237b543eaca47771b480ff194884f9c947dcaf71d6cf9"
"hash": "492edd53e497a45c314d41044e85a5e3492227b5049dc6870d60817ad929e7af"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE variable SET labels = $1 WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "4c333861e736b8138162f0ff3bf2844c71b95c75bd8f173eac51336ab176ccc0"
}

View File

@@ -70,7 +70,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script\n (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules)\n\n SELECT workspace_id, $1, path, array_prepend($2::bigint, COALESCE(parent_hashes, '{}'::bigint[])), summary, description, content, created_by, schema, is_template, extra_perms, NULL, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Int8",
"Text"
]
},
"nullable": []
},
"hash": "51f09f073842a6990535b887d8267fab305c21e4d7703bedbadf405b5c2d7582"
}

View File

@@ -34,7 +34,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -40,7 +40,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (\n id, -- 1\n workspace_id, -- 2\n raw_code, -- 3\n raw_lock, -- 4\n raw_flow, -- 5\n tag, -- 6\n parent_job, -- 7\n created_by, -- 8\n permissioned_as, -- 9\n runnable_id, -- 10\n runnable_path, -- 11\n args, -- 12\n kind, -- 13\n trigger, -- 14\n script_lang, -- 15\n same_worker, -- 16\n pre_run_error, -- 17 \n permissioned_as_email, -- 18\n visible_to_owner, -- 19\n flow_innermost_root_job, -- 20\n root_job, -- 38\n concurrent_limit, -- 21\n concurrency_time_window_s, -- 22\n timeout, -- 23\n flow_step_id, -- 24\n cache_ttl, -- 25\n priority, -- 26\n trigger_kind, -- 39\n script_entrypoint_override, -- 12\n preprocessed -- 27,\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $38, $21, $22, $23, $24, $25, $26, $39::job_trigger_kind,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27)\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id, end_user_email) \n values ($1, $32, $33, $34, $35, $36, $37, $2, $41) \n ON CONFLICT (job_id) DO UPDATE SET email = EXCLUDED.email, username = EXCLUDED.username, is_admin = EXCLUDED.is_admin, is_operator = EXCLUDED.is_operator, folders = EXCLUDED.folders, groups = EXCLUDED.groups, workspace_id = EXCLUDED.workspace_id, end_user_email = EXCLUDED.end_user_email\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority, cache_ignore_s3_path, runnable_settings_handle)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31, $42, $43)",
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (\n id, -- 1\n workspace_id, -- 2\n raw_code, -- 3\n raw_lock, -- 4\n raw_flow, -- 5\n tag, -- 6\n parent_job, -- 7\n created_by, -- 8\n permissioned_as, -- 9\n runnable_id, -- 10\n runnable_path, -- 11\n args, -- 12\n kind, -- 13\n trigger, -- 14\n script_lang, -- 15\n same_worker, -- 16\n pre_run_error, -- 17 \n permissioned_as_email, -- 18\n visible_to_owner, -- 19\n flow_innermost_root_job, -- 20\n root_job, -- 38\n concurrent_limit, -- 21\n concurrency_time_window_s, -- 22\n timeout, -- 23\n flow_step_id, -- 24\n cache_ttl, -- 25\n priority, -- 26\n trigger_kind, -- 39\n script_entrypoint_override, -- 12\n preprocessed, -- 27,\n labels -- 44\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $38, $21, $22, $23, $24, $25, $26, $39::job_trigger_kind,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27, $44)\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id, end_user_email) \n values ($1, $32, $33, $34, $35, $36, $37, $2, $41) \n ON CONFLICT (job_id) DO UPDATE SET email = EXCLUDED.email, username = EXCLUDED.username, is_admin = EXCLUDED.is_admin, is_operator = EXCLUDED.is_operator, folders = EXCLUDED.folders, groups = EXCLUDED.groups, workspace_id = EXCLUDED.workspace_id, end_user_email = EXCLUDED.end_user_email\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority, cache_ignore_s3_path, runnable_settings_handle)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31, $42, $43)",
"describe": {
"columns": [],
"parameters": {
@@ -76,7 +76,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}
@@ -131,10 +132,11 @@
"Bool",
"Varchar",
"Bool",
"Int8"
"Int8",
"TextArray"
]
},
"nullable": []
},
"hash": "14276a040cb4db88d71fccdc3579e8c0bb132b70668301b535872d1632753e30"
"hash": "5425e2c5e29fc5145dde5ea53d5307ca90d8dd76da2ca560b310b12820be2576"
}

View File

@@ -148,7 +148,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n script_lang as \"language: _\",\n COUNT(*) as \"count!\",\n SUM(duration_ms)::BIGINT as \"total_duration!\"\n FROM\n v2_job_completed\n JOIN\n v2_job\n ON\n v2_job.id = v2_job_completed.id\n WHERE\n created_at > NOW() - INTERVAL '48 hours'\n GROUP BY\n script_lang\n ",
"query": "\n SELECT\n NULLIF(script_lang, 'other')::script_lang as \"language: _\",\n SUM(job_count)::BIGINT as \"count!\",\n SUM(total_duration_ms)::BIGINT as \"total_duration!\"\n FROM worker_group_job_stats\n WHERE hour >= $1\n GROUP BY script_lang\n ",
"describe": {
"columns": [
{
@@ -33,7 +33,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}
@@ -51,13 +52,15 @@
}
],
"parameters": {
"Left": []
"Left": [
"Int8"
]
},
"nullable": [
true,
null,
null,
null
]
},
"hash": "464895f217536bf713ec381b6c3b7c0417161bf69e596e2e34fc8d9384824776"
"hash": "5c0d0c7111b70b119b3182c9195361388ead36dc6ab03c6a7c17fb97d2b60a67"
}

View File

@@ -43,7 +43,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n script_lang as \"language: _\",\n COUNT(*) as \"count!\",\n SUM(duration_ms)::BIGINT as \"total_duration!\"\n FROM\n v2_job_completed\n JOIN\n v2_job\n ON\n v2_job.id = v2_job_completed.id\n WHERE\n created_at >= CURRENT_DATE - INTERVAL '1 day'\n AND created_at < CURRENT_DATE\n GROUP BY\n script_lang\n ",
"query": "\n SELECT\n NULLIF(script_lang, 'other')::script_lang as \"language: _\",\n SUM(job_count)::BIGINT as \"count!\",\n SUM(total_duration_ms)::BIGINT as \"total_duration!\"\n FROM worker_group_job_stats\n WHERE hour >= $1 AND hour < $2\n GROUP BY script_lang\n ",
"describe": {
"columns": [
{
@@ -33,7 +33,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}
@@ -51,13 +52,16 @@
}
],
"parameters": {
"Left": []
"Left": [
"Int8",
"Int8"
]
},
"nullable": [
true,
null,
null,
null
]
},
"hash": "19478c2a3c05b2ed17b110f8ff58d48ce3ede5fdd7f8d64840f8c62cf89f99e7"
"hash": "6348061d79b0b6b25bda7425f7a37344e04107f060f949cc197b4df9bca18fb8"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE schedule SET\n enabled = $1,\n email = $2\n WHERE path = $3 AND workspace_id = $4\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip\n ",
"query": "\n UPDATE schedule SET\n enabled = $1,\n email = $2\n WHERE path = $3 AND workspace_id = $4\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip,\n labels\n ",
"describe": {
"columns": [
{
@@ -162,6 +162,11 @@
"ordinal": 31,
"name": "dynamic_skip",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -204,8 +209,9 @@
true,
true,
true,
true,
true
]
},
"hash": "ad96768ff61fab1cfb9421683bb13b64f5f157fafe114d50fb910dc36ebe0f91"
"hash": "642ca096c1c151fc01445593c8d2ed879a9a7be6ff044a9ce1b581ba725665fe"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at)\n SELECT workspace_id, $1, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at\n FROM flow\n WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "676c758d9c4492dada50edd3ad06dc628e2ba56eab5e1a50c99481da9793759e"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n flow_version.id AS version,\n flow_version.value->>'early_return' as early_return,\n flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor,\n (flow_version.value->>'chat_input_enabled')::boolean as chat_input_enabled,\n flow.tag,\n flow.dedicated_worker,\n flow.on_behalf_of_email,\n flow.edited_by\n FROM\n flow_version\n INNER JOIN flow\n ON flow.path = flow_version.path AND\n flow.workspace_id = flow_version.workspace_id\n WHERE\n flow_version.workspace_id = $1 AND\n flow_version.path = $2 AND\n flow_version.id = $3\n ",
"query": "\n SELECT\n flow_version.id AS version,\n flow_version.value->>'early_return' as early_return,\n flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor,\n (flow_version.value->>'chat_input_enabled')::boolean as chat_input_enabled,\n flow.tag,\n flow.dedicated_worker,\n flow.on_behalf_of_email,\n flow.edited_by,\n flow.labels\n FROM\n flow_version\n INNER JOIN flow\n ON flow.path = flow_version.path AND\n flow.workspace_id = flow_version.workspace_id\n WHERE\n flow_version.workspace_id = $1 AND\n flow_version.path = $2 AND\n flow_version.id = $3\n ",
"describe": {
"columns": [
{
@@ -42,6 +42,11 @@
"ordinal": 7,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -59,8 +64,9 @@
true,
true,
true,
false
false,
true
]
},
"hash": "209dc4c1b91eeab1c12ffcd9f9e16f315c689ca772c736b333dcdf07c8086087"
"hash": "6d992a933bb878733b7afd7a4295b9ad6f5276b60ce20e0378d6148976e02777"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "select hash, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, debounce_key, debounce_delay_s, cache_ttl, cache_ignore_s3_path, runnable_settings_handle, language as \"language: ScriptLang\", dedicated_worker, priority, timeout, on_behalf_of_email, created_by FROM script\n WHERE path = $1 AND workspace_id = $2 AND archived = false AND (lock IS NOT NULL OR $3 = false)\n ORDER BY created_at DESC LIMIT 1",
"query": "select hash, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, debounce_key, debounce_delay_s, cache_ttl, cache_ignore_s3_path, runnable_settings_handle, language as \"language: ScriptLang\", dedicated_worker, priority, timeout, on_behalf_of_email, created_by, labels FROM script\n WHERE path = $1 AND workspace_id = $2 AND archived = false AND (lock IS NOT NULL OR $3 = false)\n ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
@@ -83,7 +83,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}
@@ -113,6 +114,11 @@
"ordinal": 15,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 16,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -138,8 +144,9 @@
true,
true,
true,
false
false,
true
]
},
"hash": "a33673ebc4d1eb4c3513987dbc43e2c80974598e1d9fe7203145bfc29928ba65"
"hash": "71767e6684957af5dff56a1bb64f980f712f92798d11feaeb0832962ad9ddb2e"
}

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO notify_event (channel, payload) VALUES ('restart_worker_group', $1)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "78f7c4efd7be2aad03f0ec67ab882e1f9aaa7141ab75046a71ac789ab659bdc6"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, cache_ignore_s3_path, runnable_settings_handle, modules) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39)",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, cache_ignore_s3_path, runnable_settings_handle, modules, labels) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40)",
"describe": {
"columns": [],
"parameters": {
@@ -44,7 +44,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}
@@ -88,10 +89,11 @@
"Int4",
"Bool",
"Int8",
"Jsonb"
"Jsonb",
"TextArray"
]
},
"nullable": []
},
"hash": "4d983f1e3e63a1a70edf5d867d9f23f2069a7a4ba1dcc1331ecccdf1c6a95cb8"
"hash": "790d79ec7abe6ebe1092afd9de4c5fc383272d2057ac5b47a7425f095f4e8788"
}

View File

@@ -76,7 +76,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE http_trigger SET labels = $1 WHERE workspace_id = $2 AND path = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "86c0ef92652085b93979a8836bedb33a366a84426a115c75f58dcc43ab91705e"
}

View File

@@ -41,7 +41,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -153,7 +153,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -118,7 +118,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -133,7 +133,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -38,7 +38,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script\n (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules, labels)\n\n SELECT workspace_id, $1, path, array_prepend($2::bigint, COALESCE(parent_hashes, '{}'::bigint[])), summary, description, content, created_by, schema, is_template, extra_perms, NULL, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules, labels\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Int8",
"Text"
]
},
"nullable": []
},
"hash": "a969194571dd3f12e628ce0f01b0ddc09bbcf4506eff2290664c295d16fec4ae"
}

View File

@@ -153,7 +153,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -123,7 +123,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -43,7 +43,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE app SET labels = $1 WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "b657b718ec381fbb1d41841c88118b88c4d7ea8f0cde663ed8f8226faf75b0f6"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow (\n workspace_id, path, summary, description,\n dependency_job, lock_error_logs, draft_only, tag,\n dedicated_worker, visible_to_runner_only, on_behalf_of_email,\n ws_error_handler_muted,\n value, schema, edited_by, edited_at\n ) VALUES (\n $1, $2, $3, $4,\n NULL, '', $5, $6,\n $7, $8, $9,\n $10,\n $11, $12::text::json, $13, now()\n )",
"query": "INSERT INTO flow (\n workspace_id, path, summary, description,\n dependency_job, lock_error_logs, draft_only, tag,\n dedicated_worker, visible_to_runner_only, on_behalf_of_email,\n ws_error_handler_muted,\n value, schema, edited_by, edited_at, labels\n ) VALUES (\n $1, $2, $3, $4,\n NULL, '', $5, $6,\n $7, $8, $9,\n $10,\n $11, $12::text::json, $13, now(), $14\n )",
"describe": {
"columns": [],
"parameters": {
@@ -17,10 +17,11 @@
"Bool",
"Jsonb",
"Text",
"Varchar"
"Varchar",
"TextArray"
]
},
"nullable": []
},
"hash": "6bde827da007b470b9d0acccfc3e00ce6aac650b9138a236f34c614eed753849"
"hash": "b6f95b3fd1d0431d96d0409424dbb20cb3020f93454978d078082482b86cbebe"
}

View File

@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT unnest(labels) as \"label!\" FROM (\n SELECT labels FROM script WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM flow WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM resource WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM variable WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM schedule WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM app WHERE workspace_id = $1 AND labels IS NOT NULL\n ) t ORDER BY 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "label!",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "b782179261b4054289a1a595f6e06ee2035ae9811bc49abce903a04439baf800"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE schedule SET\n schedule = $1,\n timezone = $2,\n args = $3,\n on_failure = $4,\n on_failure_times = $5,\n on_failure_exact = $6,\n on_failure_extra_args = $7,\n on_recovery = $8,\n on_recovery_times = $9,\n on_recovery_extra_args = $10,\n on_success = $11,\n on_success_extra_args = $12,\n ws_error_handler_muted = $13,\n retry = $14,\n summary = $15,\n no_flow_overlap = $16,\n tag = $17,\n paused_until = $18,\n path = $19,\n workspace_id = $20,\n cron_version = COALESCE($21, cron_version),\n description = $22,\n dynamic_skip = $23,\n email = $24,\n edited_by = $25,\n permissioned_as = $26\n WHERE path = $19 AND workspace_id = $20\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip\n ",
"query": "\n UPDATE schedule SET\n schedule = $1,\n timezone = $2,\n args = $3,\n on_failure = $4,\n on_failure_times = $5,\n on_failure_exact = $6,\n on_failure_extra_args = $7,\n on_recovery = $8,\n on_recovery_times = $9,\n on_recovery_extra_args = $10,\n on_success = $11,\n on_success_extra_args = $12,\n ws_error_handler_muted = $13,\n retry = $14,\n summary = $15,\n no_flow_overlap = $16,\n tag = $17,\n paused_until = $18,\n path = $19,\n workspace_id = $20,\n cron_version = COALESCE($21, cron_version),\n description = $22,\n dynamic_skip = $23,\n email = $24,\n edited_by = $25,\n permissioned_as = $26,\n labels = COALESCE($27, labels)\n WHERE path = $19 AND workspace_id = $20\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip,\n labels\n ",
"describe": {
"columns": [
{
@@ -162,6 +162,11 @@
"ordinal": 31,
"name": "dynamic_skip",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -191,7 +196,8 @@
"Varchar",
"Varchar",
"Varchar",
"Varchar"
"Varchar",
"TextArray"
]
},
"nullable": [
@@ -226,8 +232,9 @@
true,
true,
true,
true,
true
]
},
"hash": "54b4c762add9b1ebfdb2a6d5abd6d20e86dc0e6544f0bb22fa4ec68aa54a4dc8"
"hash": "bd2609f999054c5a2a85f2aafe4005bc22731c27f0bf27b3b06ec426a05eda2e"
}

View File

@@ -40,7 +40,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -77,7 +77,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n flow\n SET\n path = $1,\n summary = $2,\n description = $3,\n dependency_job = NULL,\n lock_error_logs = '',\n draft_only = NULL,\n tag = $4,\n dedicated_worker = $5,\n visible_to_runner_only = $6,\n on_behalf_of_email = $7,\n ws_error_handler_muted = $8,\n value = $9,\n schema = $10::text::json,\n edited_by = $11,\n edited_at = now()\n WHERE\n path = $12 AND workspace_id = $13",
"query": "\n UPDATE\n flow\n SET\n path = $1,\n summary = $2,\n description = $3,\n dependency_job = NULL,\n lock_error_logs = '',\n draft_only = NULL,\n tag = $4,\n dedicated_worker = $5,\n visible_to_runner_only = $6,\n on_behalf_of_email = $7,\n ws_error_handler_muted = $8,\n value = $9,\n schema = $10::text::json,\n edited_by = $11,\n edited_at = now(),\n labels = COALESCE($14, labels)\n WHERE\n path = $12 AND workspace_id = $13",
"describe": {
"columns": [],
"parameters": {
@@ -17,10 +17,11 @@
"Text",
"Varchar",
"Text",
"Text"
"Text",
"TextArray"
]
},
"nullable": []
},
"hash": "77ac7257be02fb04c4b3213e2221e6f60621b4b2909d770de744ef5671e12ed9"
"hash": "c06796e8647cf278c6e0809562aaaa872403890eae3e606f379343671c2fff02"
}

View File

@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT value AS \"value!: Json<Box<RawValue>>\" FROM flow WHERE path = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value!: Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false
]
},
"hash": "c569535d4aded82ffef5e5066e24948c8fcdb8d36913775449b982782c8583e9"
}

View File

@@ -68,7 +68,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -77,7 +77,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels)\n SELECT workspace_id, $1, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels\n FROM flow\n WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "ddda19024473b4e5b1d450bf56c667056f6b3696dea7d73758e53f825bfce13e"
}

View File

@@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO resource\n (workspace_id, path, value, description, resource_type, created_by, edited_at, labels)\n VALUES ($1, $2, $3, $4, $5, $6, now(), $7) ON CONFLICT (workspace_id, path)\n DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now(), labels = EXCLUDED.labels",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Jsonb",
"Text",
"Varchar",
"Varchar",
"TextArray"
]
},
"nullable": []
},
"hash": "deac41298e8b0d0870e314fef0813c24dd55d63bda78a0a5f35ed6f22bea6bef"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO app\n (workspace_id, path, summary, policy, versions, draft_only, custom_path)\n VALUES ($1, $2, $3, $4, '{}', $5, $6) RETURNING id",
"query": "INSERT INTO app\n (workspace_id, path, summary, policy, versions, draft_only, custom_path, labels)\n VALUES ($1, $2, $3, $4, '{}', $5, $6, $7) RETURNING id",
"describe": {
"columns": [
{
@@ -16,12 +16,13 @@
"Varchar",
"Jsonb",
"Bool",
"Text"
"Text",
"TextArray"
]
},
"nullable": [
false
]
},
"hash": "6b53f7c4bb73177316d6134698f3979f51b53dcd4d8ec50d312c9e7fe31ad5f5"
"hash": "e4836a1ee97e4723bddc28b94e23a54b6aa1f458f3ecca8f35432153e54b143d"
}

View File

@@ -133,7 +133,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -0,0 +1,64 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, name, language AS \"language: windmill_common::scripts::ScriptLang\"\n FROM workspace_dependencies\n WHERE archived = false\n ORDER BY workspace_id, name",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "language: windmill_common::scripts::ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang"
]
}
}
}
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
true,
false
]
},
"hash": "edd6c09b7f012588788fd3c572d20eb439a80d52ae75ebd25128ffce759cd313"
}

View File

@@ -0,0 +1,72 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT ON (workspace_id, path)\n workspace_id, path, language AS \"language: windmill_common::scripts::ScriptLang\", content\n FROM script\n WHERE archived = false\n AND dedicated_worker = true\n AND language = ANY($1::text[]::SCRIPT_LANG[])\n ORDER BY workspace_id, path, created_at DESC",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "language: windmill_common::scripts::ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang"
]
}
}
}
},
{
"ordinal": 3,
"name": "content",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"TextArray"
]
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "f0858450021df721d8a48b1b5dc887c5424562acd9769c80c5899193ef16b56b"
}

View File

@@ -40,7 +40,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -38,7 +38,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}
@@ -84,7 +85,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -33,7 +33,8 @@
"nu",
"java",
"duckdb",
"ruby"
"ruby",
"rlang"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE resource SET labels = $1 WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "f6f850c419771b193f506ceca63de805cbe6bdee314ca40d912010db307bd13e"
}

296
backend/Cargo.lock generated
View File

@@ -2108,7 +2108,7 @@ dependencies = [
"rayon",
"safetensors",
"thiserror 2.0.18",
"yoke 0.8.1",
"yoke 0.8.2",
"zip",
]
@@ -2373,9 +2373,9 @@ dependencies = [
[[package]]
name = "cmov"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0758edba32d61d1fd9f4d69491b47604b91ee2f7e6b33de7e54ca4ebe55dc3"
checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746"
[[package]]
name = "codespan-reporting"
@@ -2805,9 +2805,9 @@ dependencies = [
[[package]]
name = "ctutils"
version = "0.4.0"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1005a6d4446f5120ef475ad3d2af2b30c49c2c9c6904258e3bb30219bebed5e4"
checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
dependencies = [
"cmov",
]
@@ -7224,22 +7224,23 @@ dependencies = [
[[package]]
name = "icu_collections"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
dependencies = [
"displaydoc",
"potential_utf",
"yoke 0.8.1",
"utf8_iter",
"yoke 0.8.2",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
dependencies = [
"displaydoc",
"litemap",
@@ -7250,9 +7251,9 @@ dependencies = [
[[package]]
name = "icu_normalizer"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
dependencies = [
"icu_collections",
"icu_normalizer_data",
@@ -7264,15 +7265,15 @@ dependencies = [
[[package]]
name = "icu_normalizer_data"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
[[package]]
name = "icu_properties"
version = "2.1.2"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
dependencies = [
"icu_collections",
"icu_locale_core",
@@ -7284,20 +7285,20 @@ dependencies = [
[[package]]
name = "icu_properties_data"
version = "2.1.2"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
[[package]]
name = "icu_provider"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke 0.8.1",
"yoke 0.8.2",
"zerofrom",
"zerotrie",
"zerovec",
@@ -8046,9 +8047,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.183"
version = "0.2.184"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
[[package]]
name = "libffi"
@@ -8204,9 +8205,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litemap"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "litrs"
@@ -10427,9 +10428,9 @@ dependencies = [
[[package]]
name = "potential_utf"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
dependencies = [
"zerovec",
]
@@ -12117,6 +12118,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71"
[[package]]
name = "scc"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc"
dependencies = [
"sdd",
]
[[package]]
name = "schannel"
version = "0.1.29"
@@ -12222,6 +12232,12 @@ dependencies = [
"untrusted 0.9.0",
]
[[package]]
name = "sdd"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca"
[[package]]
name = "seahash"
version = "4.1.0"
@@ -12558,6 +12574,32 @@ dependencies = [
"serde",
]
[[package]]
name = "serial_test"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f"
dependencies = [
"futures-executor",
"futures-util",
"log",
"once_cell",
"parking_lot",
"scc",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "sha1"
version = "0.10.6"
@@ -14235,9 +14277,9 @@ dependencies = [
[[package]]
name = "tinystr"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
dependencies = [
"displaydoc",
"zerovec",
@@ -14625,9 +14667,9 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.1.1+spec-1.1.0"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ca317ebc49f06bd748bfba29533eac9485569dc9bf80b849024b025e814fb9"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow 1.0.1",
]
@@ -15941,7 +15983,7 @@ dependencies = [
[[package]]
name = "windmill"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-nats",
@@ -15970,6 +16012,7 @@ dependencies = [
"serde_derive",
"serde_json",
"serde_yml",
"serial_test",
"sha1",
"sha2 0.10.9",
"sql-builder",
@@ -16019,7 +16062,7 @@ dependencies = [
[[package]]
name = "windmill-alerting"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16032,7 +16075,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"argon2",
@@ -16173,7 +16216,7 @@ dependencies = [
[[package]]
name = "windmill-api-agent-workers"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16196,7 +16239,7 @@ dependencies = [
[[package]]
name = "windmill-api-assets"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16209,7 +16252,7 @@ dependencies = [
[[package]]
name = "windmill-api-auth"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16235,7 +16278,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"reqwest 0.12.28",
"serde",
@@ -16245,7 +16288,7 @@ dependencies = [
[[package]]
name = "windmill-api-configs"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16262,7 +16305,7 @@ dependencies = [
[[package]]
name = "windmill-api-debug"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"base64 0.22.1",
@@ -16285,7 +16328,7 @@ dependencies = [
[[package]]
name = "windmill-api-embeddings"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16308,7 +16351,7 @@ dependencies = [
[[package]]
name = "windmill-api-flow-conversations"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16324,7 +16367,7 @@ dependencies = [
[[package]]
name = "windmill-api-flows"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16344,7 +16387,7 @@ dependencies = [
[[package]]
name = "windmill-api-groups"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16364,7 +16407,7 @@ dependencies = [
[[package]]
name = "windmill-api-inputs"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16378,7 +16421,7 @@ dependencies = [
[[package]]
name = "windmill-api-integration-tests"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-nats",
@@ -16409,7 +16452,7 @@ dependencies = [
[[package]]
name = "windmill-api-jobs"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16434,7 +16477,7 @@ dependencies = [
[[package]]
name = "windmill-api-npm-proxy"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"flate2",
@@ -16452,7 +16495,7 @@ dependencies = [
[[package]]
name = "windmill-api-openapi"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16474,7 +16517,7 @@ dependencies = [
[[package]]
name = "windmill-api-schedule"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16494,7 +16537,7 @@ dependencies = [
[[package]]
name = "windmill-api-scripts"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16524,7 +16567,7 @@ dependencies = [
[[package]]
name = "windmill-api-settings"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16551,7 +16594,7 @@ dependencies = [
[[package]]
name = "windmill-api-sse"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"lazy_static",
"serde",
@@ -16563,7 +16606,7 @@ dependencies = [
[[package]]
name = "windmill-api-users"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"argon2",
"axum 0.8.4",
@@ -16588,7 +16631,7 @@ dependencies = [
[[package]]
name = "windmill-api-workers"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16602,7 +16645,7 @@ dependencies = [
[[package]]
name = "windmill-api-workspaces"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16634,7 +16677,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"chrono",
"lazy_static",
@@ -16648,7 +16691,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16667,7 +16710,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"aes-gcm",
"aho-corasick",
@@ -16769,7 +16812,7 @@ dependencies = [
[[package]]
name = "windmill-dep-map"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"chrono",
"itertools 0.14.0",
@@ -16788,7 +16831,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"regex",
"serde",
@@ -16803,7 +16846,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"astral-tokio-tar",
@@ -16827,7 +16870,7 @@ dependencies = [
[[package]]
name = "windmill-jseval"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"futures",
@@ -16844,7 +16887,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -16860,7 +16903,7 @@ dependencies = [
[[package]]
name = "windmill-mcp"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16881,7 +16924,7 @@ dependencies = [
[[package]]
name = "windmill-native-triggers"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16912,7 +16955,7 @@ dependencies = [
[[package]]
name = "windmill-oauth"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-oauth2",
@@ -16936,7 +16979,7 @@ dependencies = [
[[package]]
name = "windmill-object-store"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-stream",
@@ -16970,7 +17013,7 @@ dependencies = [
[[package]]
name = "windmill-operator"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"futures",
@@ -16988,7 +17031,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -16997,7 +17040,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17009,7 +17052,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17021,7 +17064,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"gosyn",
@@ -17033,7 +17076,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17045,7 +17088,7 @@ dependencies = [
[[package]]
name = "windmill-parser-java"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17057,7 +17100,7 @@ dependencies = [
[[package]]
name = "windmill-parser-nu"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"nu-parser",
@@ -17068,7 +17111,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -17079,7 +17122,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -17091,7 +17134,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-asset"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -17102,7 +17145,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17124,7 +17167,7 @@ dependencies = [
[[package]]
name = "windmill-parser-r"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17136,7 +17179,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ruby"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17150,7 +17193,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -17167,7 +17210,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17180,7 +17223,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql-asset"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"serde",
@@ -17192,7 +17235,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17210,7 +17253,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts-asset"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"serde-wasm-bindgen",
@@ -17226,7 +17269,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wac"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -17242,7 +17285,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"serde",
@@ -17253,7 +17296,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17290,7 +17333,7 @@ dependencies = [
[[package]]
name = "windmill-runtime-nativets"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"const_format",
@@ -17328,7 +17371,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"getrandom 0.3.4",
"wasm-bindgen",
@@ -17339,7 +17382,7 @@ dependencies = [
[[package]]
name = "windmill-store"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17368,7 +17411,7 @@ dependencies = [
[[package]]
name = "windmill-test-utils"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17392,7 +17435,7 @@ dependencies = [
[[package]]
name = "windmill-trigger"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17425,7 +17468,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-email"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17445,7 +17488,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-gcp"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17479,7 +17522,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-http"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17515,7 +17558,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-kafka"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17538,7 +17581,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-mqtt"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17562,7 +17605,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-nats"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-nats",
@@ -17586,7 +17629,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-postgres"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17621,7 +17664,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-sqs"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17649,7 +17692,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-websocket"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17672,7 +17715,7 @@ dependencies = [
[[package]]
name = "windmill-types"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"bitflags 2.9.4",
@@ -17691,7 +17734,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"anyhow",
"async-once-cell",
@@ -17795,13 +17838,14 @@ dependencies = [
"windmill-runtime-nativets",
"windmill-types",
"windmill-worker-volumes",
"windows 0.61.3",
"x509-parser 0.16.0",
"yaml-rust",
]
[[package]]
name = "windmill-worker-volumes"
version = "1.672.0"
version = "1.673.0"
dependencies = [
"bytes",
"futures",
@@ -18501,9 +18545,9 @@ dependencies = [
[[package]]
name = "writeable"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
[[package]]
name = "wtf8"
@@ -18636,12 +18680,12 @@ dependencies = [
[[package]]
name = "yoke"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
dependencies = [
"stable_deref_trait",
"yoke-derive 0.8.1",
"yoke-derive 0.8.2",
"zerofrom",
]
@@ -18659,9 +18703,9 @@ dependencies = [
[[package]]
name = "yoke-derive"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
@@ -18691,18 +18735,18 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
@@ -18732,31 +18776,31 @@ dependencies = [
[[package]]
name = "zerotrie"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
dependencies = [
"displaydoc",
"yoke 0.8.1",
"yoke 0.8.2",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.5"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
dependencies = [
"yoke 0.8.1",
"yoke 0.8.2",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.672.0"
version = "1.673.0"
authors.workspace = true
edition.workspace = true
@@ -85,7 +85,7 @@ members = [
exclude = ["./windmill-duckdb-ffi-internal", "./parsers/windmill-parser-wasm"]
[workspace.package]
version = "1.672.0"
version = "1.673.0"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -267,6 +267,7 @@ windmill-types.workspace = true
opentelemetry = { workspace = true }
opentelemetry_sdk = { workspace = true }
windmill-trigger.workspace = true
serial_test = "3"
windmill-trigger-websocket.workspace = true
windmill-trigger-postgres.workspace = true
windmill-trigger-mqtt.workspace = true
@@ -577,7 +578,7 @@ async-stream = "^0"
opentelemetry = "0.30.0"
tracing-opentelemetry = "0.31.0"
opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio", "testing"] }
opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic", "tls"] }
opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic", "tls", "http-proto"] }
opentelemetry-appender-tracing = "0.30.0"
opentelemetry-semantic-conventions = { version = "0.30.0", features = ["semconv_experimental"] }
opentelemetry-proto = { version = "0.30.0", features = ["with-serde", "gen-tonic"] }

View File

@@ -1 +1 @@
e08a87450627bef9013498e40ee93a47bedda7ee
ef37ca96f140dcd553226fac6bce3ef6d57ec03d

View File

@@ -0,0 +1,16 @@
ALTER TABLE script DROP COLUMN IF EXISTS labels;
ALTER TABLE flow DROP COLUMN IF EXISTS labels;
ALTER TABLE app DROP COLUMN IF EXISTS labels;
ALTER TABLE raw_app DROP COLUMN IF EXISTS labels;
ALTER TABLE schedule DROP COLUMN IF EXISTS labels;
ALTER TABLE http_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE websocket_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE kafka_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE nats_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE mqtt_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE postgres_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE sqs_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE gcp_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE email_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE resource DROP COLUMN IF EXISTS labels;
ALTER TABLE variable DROP COLUMN IF EXISTS labels;

View File

@@ -0,0 +1,33 @@
ALTER TABLE script ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE flow ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE app ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE raw_app ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE schedule ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE http_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE websocket_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE kafka_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE nats_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE mqtt_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE postgres_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE sqs_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE gcp_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE email_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE resource ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE variable ADD COLUMN IF NOT EXISTS labels text[];
CREATE INDEX IF NOT EXISTS idx_script_labels ON script USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_flow_labels ON flow USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_app_labels ON app USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_raw_app_labels ON raw_app USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_schedule_labels ON schedule USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_resource_labels ON resource USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_variable_labels ON variable USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_http_trigger_labels ON http_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_websocket_trigger_labels ON websocket_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_kafka_trigger_labels ON kafka_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_nats_trigger_labels ON nats_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_mqtt_trigger_labels ON mqtt_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_postgres_trigger_labels ON postgres_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_sqs_trigger_labels ON sqs_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_gcp_trigger_labels ON gcp_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_email_trigger_labels ON email_trigger USING GIN (labels) WHERE labels IS NOT NULL;

View File

@@ -0,0 +1,6 @@
-- Remove the //nodejs annotation that was prepended by the up migration.
-- Only removes it if it's at the very start of the content.
UPDATE script
SET content = regexp_replace(content, E'^//nodejs\n// dedicated workers were previously running in nodejs mode by default, remove this annotation to use bun\n', '')
WHERE language = 'bun'
AND dedicated_worker = true;

View File

@@ -0,0 +1,10 @@
-- Bun dedicated workers were previously forced to run in nodejs mode at runtime.
-- Now that bun is the default again, add the //nodejs annotation to existing
-- bun dedicated scripts that don't already have it, so their behavior is preserved.
UPDATE script
SET content = '//nodejs
// dedicated workers were previously running in nodejs mode by default, remove this annotation to use bun
' || content
WHERE language = 'bun'
AND dedicated_worker = true
AND content !~ '^//\s*nodejs';

View File

@@ -0,0 +1 @@
ALTER TABLE websocket_trigger DROP COLUMN heartbeat;

View File

@@ -0,0 +1 @@
ALTER TABLE websocket_trigger ADD COLUMN heartbeat JSONB NULL;

View File

@@ -22,22 +22,82 @@ pub fn parse_bash_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing bash script".to_string()))
}
}
/// PowerShell common parameter names that are automatically added by [CmdletBinding()].
/// These should be filtered from the parsed signature since they are not user-defined.
const POWERSHELL_COMMON_PARAMS: &[&str] = &[
"verbose",
"debug",
"erroraction",
"errorvariable",
"informationaction",
"informationvariable",
"outvariable",
"outbuffer",
"pipelinevariable",
"warningaction",
"warningvariable",
"whatif",
"confirm",
"progressaction",
];
/// Detects whether the script uses [CmdletBinding()] and whether it declares SupportsShouldProcess.
fn detect_cmdlet_binding(code: &str) -> (bool, bool) {
let attr_region = match extract_powershell_param_block_with_attributes(code, true) {
Some((region, _)) => region,
None => return (false, false),
};
// Strip comment lines to avoid false positives from commented-out [CmdletBinding()]
let uncommented: String = attr_region
.lines()
.filter(|line| !line.trim_start().starts_with('#'))
.collect::<Vec<_>>()
.join("\n");
let lower = uncommented.to_lowercase();
let has_cmd_binding = lower.contains("[cmdletbinding");
let supports_should_process = has_cmd_binding
&& lower.contains("supportsshouldprocess")
&& !lower.contains("supportsshouldprocess=$false")
&& !lower.contains("supportsshouldprocess = $false");
(has_cmd_binding, supports_should_process)
}
pub fn parse_powershell_sig(code: &str) -> anyhow::Result<MainArgSignature> {
let parsed = parse_powershell_file(&code)?;
if let Some(x) = parsed {
let args = x;
if let Some(args) = parsed {
let (has_cmd_binding, supports_should_process) = detect_cmdlet_binding(code);
// Filter out common parameters only when CmdletBinding is present
// (without CmdletBinding, $Verbose etc. are regular user-defined parameters)
let args = if has_cmd_binding {
args.into_iter()
.filter(|arg| !POWERSHELL_COMMON_PARAMS.contains(&arg.name.to_lowercase().as_str()))
.collect()
} else {
args
};
Ok(MainArgSignature {
star_args: false,
star_kwargs: false,
args,
auto_kind: None,
has_preprocessor: None,
has_cmd_binding: if has_cmd_binding { Some(true) } else { None },
supports_should_process: if supports_should_process {
Some(true)
} else {
None
},
..Default::default()
})
} else {
Err(anyhow!("Error parsing powershell script".to_string()))
@@ -96,7 +156,10 @@ fn parse_bash_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
/// This function uses the existing extract_powershell_param_block validation, which already
/// ensures that only comments, whitespace, and attributes appear before param. So we can
/// simply return everything from the beginning to the end of the param block.
pub fn extract_powershell_param_block_with_attributes(code: &str, include_attributes: bool) -> Option<(&str, &str)> {
pub fn extract_powershell_param_block_with_attributes(
code: &str,
include_attributes: bool,
) -> Option<(&str, &str)> {
// First, use the existing function to validate and find the param block
let param_block = extract_powershell_param_block(code, true)?;
@@ -450,11 +513,15 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
// Check if this is a Parameter attribute with Mandatory (case-insensitive)
let lower = bracket_content.to_lowercase();
if lower.starts_with("parameter(") || lower.starts_with("parameter ") {
if lower.starts_with("parameter(")
|| lower.starts_with("parameter ")
{
// Check for Mandatory (case-insensitive)
if lower.contains("mandatory") {
// Check if it's explicitly set to false
if !lower.contains("mandatory=$false") && !lower.contains("mandatory = $false") {
if !lower.contains("mandatory=$false")
&& !lower.contains("mandatory = $false")
{
is_mandatory = true;
}
}
@@ -471,7 +538,11 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
// Check if this looks like a type (simple word, possibly with [])
let is_type = !bracket_content.contains('(')
&& !bracket_content.contains('=')
&& (bracket_content.chars().next().unwrap_or(' ').is_alphabetic()
&& (bracket_content
.chars()
.next()
.unwrap_or(' ')
.is_alphabetic()
|| bracket_content.starts_with('['));
if is_type && !found_dollar {
@@ -529,7 +600,9 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
while let Some((i, ch)) = chars.peek().copied() {
if in_string {
if ch == string_char && content.chars().nth(i.saturating_sub(1)) != Some('`') {
if ch == string_char
&& content.chars().nth(i.saturating_sub(1)) != Some('`')
{
in_string = false;
default_end = i + 1;
chars.next();
@@ -544,7 +617,9 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
chars.next();
} else if ch == ',' {
break;
} else if ch.is_whitespace() && chars.clone().skip(1).next().map(|(_, c)| c) == Some(',') {
} else if ch.is_whitespace()
&& chars.clone().skip(1).next().map(|(_, c)| c) == Some(',')
{
break;
} else {
default_end = i + 1;
@@ -552,12 +627,19 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
}
}
default_value = Some(content[default_start..default_end].trim().to_string());
default_value =
Some(content[default_start..default_end].trim().to_string());
}
',' => {
// End of parameter, finalize it
if let Some(name) = var_name.take() {
args.push(finalize_parameter(name, type_annotation.take(), default_value.take(), is_mandatory, validate_set.take())?);
args.push(finalize_parameter(
name,
type_annotation.take(),
default_value.take(),
is_mandatory,
validate_set.take(),
)?);
}
// Reset for next parameter
@@ -576,7 +658,13 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
// Finalize last parameter
if let Some(name) = var_name {
args.push(finalize_parameter(name, type_annotation, default_value, is_mandatory, validate_set)?);
args.push(finalize_parameter(
name,
type_annotation,
default_value,
is_mandatory,
validate_set,
)?);
}
Ok(args)
@@ -722,7 +810,8 @@ non_required="${5:-}"
}
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -813,14 +902,19 @@ non_required="${5:-}"
Arg {
otyp: Some("string".to_string()), // [string] (last type bracket with Mandatory and ValidateSet)
name: "Message".to_string(),
typ: Typ::Str(Some(vec!["Green".to_string(), "Blue".to_string(), "Red".to_string()])), // ValidateSet enum
typ: Typ::Str(Some(vec![
"Green".to_string(),
"Blue".to_string(),
"Red".to_string()
])), // ValidateSet enum
default: None,
has_default: false, // Required (Mandatory attribute)
oidx: None
}
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
Ok(())
@@ -970,19 +1064,13 @@ non_required="${5:-}"
// Valid: CmdletBinding with comments
assert_eq!(
extract_powershell_param_block(
"# My function\n[CmdletBinding()]\nparam($Name)",
false
),
extract_powershell_param_block("# My function\n[CmdletBinding()]\nparam($Name)", false),
Some("$Name")
);
// Valid: CmdletBinding with whitespace variations
assert_eq!(
extract_powershell_param_block(
"[CmdletBinding()] \n param($Name)",
false
),
extract_powershell_param_block("[CmdletBinding()] \n param($Name)", false),
Some("$Name")
);
@@ -1204,17 +1292,32 @@ param(
// Test with CmdletBinding with parameters
let code3 = "[CmdletBinding(DefaultParameterSetName='ByName')]\nparam($Name, $Id)";
let result3 = extract_powershell_param_block_with_attributes(code3, true);
assert_eq!(result3, Some(("[CmdletBinding(DefaultParameterSetName='ByName')]\nparam($Name, $Id)", "")));
assert_eq!(
result3,
Some((
"[CmdletBinding(DefaultParameterSetName='ByName')]\nparam($Name, $Id)",
""
))
);
// Test with multiple attributes
let code4 = "[CmdletBinding()]\n[OutputType([string])]\nparam($Value)";
let result4 = extract_powershell_param_block_with_attributes(code4, true);
assert_eq!(result4, Some(("[CmdletBinding()]\n[OutputType([string])]\nparam($Value)", "")));
assert_eq!(
result4,
Some((
"[CmdletBinding()]\n[OutputType([string])]\nparam($Value)",
""
))
);
// Test with comment before attributes
let code5 = "# My function\n[CmdletBinding()]\nparam($Name)";
let result5 = extract_powershell_param_block_with_attributes(code5, true);
assert_eq!(result5, Some(("# My function\n[CmdletBinding()]\nparam($Name)", "")));
assert_eq!(
result5,
Some(("# My function\n[CmdletBinding()]\nparam($Name)", ""))
);
// Test with include_attributes = false (should only get param block, not attributes)
let code6 = "[CmdletBinding()]\nparam($Name)";
@@ -1224,7 +1327,10 @@ param(
// Test with code after param
let code7 = "[CmdletBinding()]\nparam($Name)\nWrite-Host 'Hello'";
let result7 = extract_powershell_param_block_with_attributes(code7, true);
assert_eq!(result7, Some(("[CmdletBinding()]\nparam($Name)", "\nWrite-Host 'Hello'")));
assert_eq!(
result7,
Some(("[CmdletBinding()]\nparam($Name)", "\nWrite-Host 'Hello'"))
);
// Test with code after param (without attributes)
let code8 = "[CmdletBinding()]\nparam($Name)\nWrite-Host 'Hello'";
@@ -1392,10 +1498,85 @@ param(
}
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
Ok(())
}
#[test]
fn test_detect_cmdlet_binding() {
// Basic CmdletBinding
let (has_cb, has_ssp) = detect_cmdlet_binding("[CmdletBinding()]\nparam($Name)");
assert!(has_cb);
assert!(!has_ssp);
// CmdletBinding with SupportsShouldProcess
let (has_cb, has_ssp) =
detect_cmdlet_binding("[CmdletBinding(SupportsShouldProcess=$true)]\nparam($Path)");
assert!(has_cb);
assert!(has_ssp);
// CmdletBinding with SupportsShouldProcess=false
let (has_cb, has_ssp) =
detect_cmdlet_binding("[CmdletBinding(SupportsShouldProcess=$false)]\nparam($Path)");
assert!(has_cb);
assert!(!has_ssp);
// No CmdletBinding
let (has_cb, has_ssp) = detect_cmdlet_binding("param($Name)");
assert!(!has_cb);
assert!(!has_ssp);
// Case insensitive
let (has_cb, has_ssp) =
detect_cmdlet_binding("[cmdletbinding(supportsshouldprocess=$true)]\nparam($X)");
assert!(has_cb);
assert!(has_ssp);
// Commented out CmdletBinding should NOT be detected
let (has_cb, has_ssp) =
detect_cmdlet_binding("# [CmdletBinding(SupportsShouldProcess=$true)]\nparam($Path)");
assert!(!has_cb);
assert!(!has_ssp);
}
#[test]
fn test_powershell_common_param_filtering() -> anyhow::Result<()> {
// Common parameters declared in param() should be filtered out
let code = r#"[CmdletBinding()]
param(
[string]$Name,
[switch]$Verbose,
[string]$ErrorAction,
[int]$Age
)"#;
let sig = parse_powershell_sig(code)?;
assert_eq!(sig.args.len(), 2);
assert_eq!(sig.args[0].name, "Name");
assert_eq!(sig.args[1].name, "Age");
assert_eq!(sig.has_cmd_binding, Some(true));
assert_eq!(sig.supports_should_process, None);
Ok(())
}
#[test]
fn test_powershell_sig_cmdlet_binding_metadata() -> anyhow::Result<()> {
// Script without CmdletBinding
let code = "param([string]$Name)";
let sig = parse_powershell_sig(code)?;
assert_eq!(sig.has_cmd_binding, None);
assert_eq!(sig.supports_should_process, None);
// Script with CmdletBinding + SupportsShouldProcess
let code = "[CmdletBinding(SupportsShouldProcess=$true)]\nparam([string]$Path)";
let sig = parse_powershell_sig(code)?;
assert_eq!(sig.has_cmd_binding, Some(true));
assert_eq!(sig.supports_should_process, Some(true));
assert_eq!(sig.args.len(), 1);
assert_eq!(sig.args[0].name, "Path");
Ok(())
}
}

View File

@@ -89,6 +89,7 @@ pub fn parse_csharp_sig_meta(code: &str) -> anyhow::Result<CsharpMainSigMeta> {
args,
has_preprocessor: None,
auto_kind,
..Default::default()
};
Ok(CsharpMainSigMeta { is_async, returns_void, class_name, main_sig, is_public })

View File

@@ -43,6 +43,7 @@ pub fn parse_go_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -51,6 +52,7 @@ pub fn parse_go_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: None,
..Default::default()
})
}
}
@@ -244,7 +246,8 @@ func main(x int, y string, z bool, l []string, o struct { Name string `json:"nam
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);

View File

@@ -21,6 +21,7 @@ pub fn parse_graphql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -126,7 +127,8 @@ query($i: Int, $arr: [String]!, $wahoo: String = "wahoo") {
}
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);

View File

@@ -81,6 +81,7 @@ pub fn parse_java_sig_meta(code: &str) -> anyhow::Result<JavaMainSigMeta> {
args,
has_preprocessor: None,
auto_kind,
..Default::default()
};
Ok(JavaMainSigMeta { returns_void, class_name, main_sig, is_public })

View File

@@ -56,6 +56,7 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -83,6 +84,7 @@ mod test {
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -120,6 +122,7 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -232,6 +235,7 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -279,6 +283,7 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -343,6 +348,7 @@ mod test {
// },],
// auto_kind: None,
// has_preprocessor: None,
// ..Default::default()
// },
// sig
// );
@@ -373,6 +379,7 @@ mod test {
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -420,6 +427,7 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -448,6 +456,7 @@ mod test {
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -480,6 +489,7 @@ mod test {
// },],
// auto_kind: None,
// has_preprocessor: None,
// ..Default::default()
// },
// sig
// );
@@ -542,6 +552,7 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -635,6 +646,7 @@ mod test {
// ],
// auto_kind: None,
// has_preprocessor: None,
// ..Default::default()
// },
// sig
// );

View File

@@ -101,6 +101,7 @@ pub fn parse_php_signature(
args,
auto_kind: None,
has_preprocessor,
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -109,6 +110,7 @@ pub fn parse_php_signature(
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor,
..Default::default()
})
}
}
@@ -180,7 +182,8 @@ function main(string $input1 = \"hey\", bool $input2 = false, int $input3 = 3, f
}
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);

View File

@@ -366,6 +366,7 @@ pub fn parse_python_signature(
Some("lib".to_string())
},
has_preprocessor: Some(has_preprocessor),
..Default::default()
});
}
@@ -477,6 +478,7 @@ pub fn parse_python_signature(
.collect(),
auto_kind: None,
has_preprocessor: Some(has_preprocessor),
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -489,6 +491,7 @@ pub fn parse_python_signature(
None
},
has_preprocessor: Some(has_preprocessor),
..Default::default()
})
}
}
@@ -755,7 +758,8 @@ def main(test1: str, name: datetime.datetime = datetime.now(), byte: bytes = byt
},
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -820,7 +824,8 @@ def main(test1: str,
}
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -880,7 +885,8 @@ def main(test1: str,
}
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -924,7 +930,8 @@ def main(test1: Literal["foo", "bar"], test2: List[Literal["foo", "bar"]]): retu
}
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -955,7 +962,8 @@ def main(test1: DynSelect_foo): return
oidx: None
}],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -979,7 +987,8 @@ def hello(): return
star_kwargs: false,
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -1007,7 +1016,8 @@ def main(): return
star_kwargs: false,
args: vec![],
auto_kind: None,
has_preprocessor: Some(true)
has_preprocessor: Some(true),
..Default::default()
}
);
@@ -1072,7 +1082,8 @@ def main(a: list, e: List[int], b: list = [1,2,3,4], c = [1,2,3,4], d = ["a", "b
}
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -1121,7 +1132,8 @@ def main(a: str, b: Optional[str], c: str | None): return
},
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);

View File

@@ -30,6 +30,7 @@ pub fn parse_r_sig_meta(code: &str) -> anyhow::Result<MainArgSignature> {
args: args.unwrap_or_default(),
has_preprocessor: None,
auto_kind: None,
..Default::default()
};
Ok(main_sig)

View File

@@ -41,6 +41,7 @@ pub fn parse_ruby_sig_meta(code: &str) -> anyhow::Result<MainArgSignature> {
args: args.unwrap_or_default(),
has_preprocessor: None,
auto_kind,
..Default::default()
};
Ok(main_sig)

View File

@@ -30,6 +30,7 @@ pub fn parse_rust_signature(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -38,6 +39,7 @@ pub fn parse_rust_signature(code: &str) -> anyhow::Result<MainArgSignature> {
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: None,
..Default::default()
})
}
}

View File

@@ -30,6 +30,7 @@ pub fn parse_mysql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -46,6 +47,7 @@ pub fn parse_oracledb_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -67,6 +69,7 @@ pub fn parse_pgsql_sig_with_typed_schema(code: &str) -> anyhow::Result<(MainArgS
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
typed_schema,
))
@@ -85,6 +88,7 @@ pub fn parse_bigquery_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -100,6 +104,7 @@ pub fn parse_duckdb_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -116,6 +121,7 @@ pub fn parse_snowflake_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -132,6 +138,7 @@ pub fn parse_mssql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -944,7 +951,8 @@ SELECT * FROM table WHERE token=$1::TEXT AND image=$2::BIGINT
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -993,7 +1001,8 @@ SELECT $2::TEXT;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1120,7 +1129,8 @@ SELECT ?, ?;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1168,7 +1178,8 @@ SELECT :param2;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1208,7 +1219,8 @@ SELECT @token;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1256,7 +1268,8 @@ SELECT ?;
}
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1304,7 +1317,8 @@ SELECT @P2;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1353,7 +1367,8 @@ SELECT * FROM table_name WHERE thing = :name4;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1391,7 +1406,8 @@ SELECT * FROM users WHERE id = $1 AND email = $2::text;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1429,7 +1445,8 @@ SELECT * FROM users LIMIT $1 OFFSET $2;
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1479,7 +1496,8 @@ WHERE id = $1
},
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1506,7 +1524,8 @@ SELECT * FROM users WHERE id = ANY($1);
oidx: Some(1),
},],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1535,7 +1554,8 @@ SELECT $1::integer;
oidx: Some(1),
},],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);
@@ -1567,7 +1587,8 @@ SELECT x
oidx: None,
},],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);

View File

@@ -462,6 +462,7 @@ pub fn parse_deno_signature(
},
auto_kind,
has_preprocessor: Some(has_preprocessor),
..Default::default()
};
Ok(r)
}

View File

@@ -47,6 +47,7 @@ mod tests {
args: vec![],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -105,6 +106,7 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -154,6 +156,7 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -203,6 +206,7 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -234,6 +238,7 @@ mod tests {
},],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -265,6 +270,7 @@ mod tests {
},],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -305,6 +311,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -343,6 +350,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -401,6 +409,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -459,6 +468,7 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -508,6 +518,7 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -557,6 +568,7 @@ mod tests {
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -584,6 +596,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -613,6 +626,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -642,6 +656,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -691,6 +706,7 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -731,6 +747,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(true),
..Default::default()
}
);
}
@@ -761,6 +778,7 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(true),
..Default::default()
}
);
}

View File

@@ -141,7 +141,8 @@ export function main(test1?: string, test2: string = \"burkina\",
}
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -220,7 +221,8 @@ export function main(test2 = \"burkina\",
}
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -271,7 +273,8 @@ export function main(foo: FooBar, {a, b}: FooBar, {c, d}: FooBar = {a: \"foo\",
}
],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -303,7 +306,8 @@ export function main(foo: (\"foo\" | \"bar\")[]) {
oidx: None
}],
auto_kind: None,
has_preprocessor: Some(false)
has_preprocessor: Some(false),
..Default::default()
}
);
@@ -447,7 +451,8 @@ Write-Output 'Testing...'
}
],
auto_kind: None,
has_preprocessor: None
has_preprocessor: None,
..Default::default()
}
);

View File

@@ -27,6 +27,7 @@ pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result<MainArgSignature
args: vec![],
auto_kind: None,
has_preprocessor: None,
..Default::default()
});
}
@@ -94,6 +95,7 @@ pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result<MainArgSignature
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
}

View File

@@ -38,6 +38,10 @@ pub struct MainArgSignature {
pub args: Vec<Arg>,
pub auto_kind: Option<String>,
pub has_preprocessor: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_cmd_binding: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_should_process: Option<bool>,
}
#[derive(Serialize, Clone, Debug, PartialEq)]

View File

@@ -41,50 +41,69 @@ pub async fn connect_db(
};
let pool = connect(database_url.clone(), max_connections, worker_mode).await?;
#[cfg(all(feature = "enterprise", feature = "private"))]
let pool2 = pool.clone();
#[cfg(all(feature = "enterprise", feature = "private"))]
if let DatabaseUrl::IamRds(database_url) = database_url {
tokio::spawn(async move {
loop {
tokio::select! {
_ = killpill_rx.recv() => {
break;
}
_ = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
let needs_refresh = {
let read_guard = database_url.read().await;
read_guard.needs_refresh()
};
if needs_refresh {
let new_url = tokio::time::timeout(std::time::Duration::from_secs(10), get_database_url()).await;
{
let needs_token_refresh = matches!(
database_url,
DatabaseUrl::IamRds(_) | DatabaseUrl::EntraId(_)
);
let label = match &database_url {
DatabaseUrl::IamRds(_) => "IAM RDS",
DatabaseUrl::EntraId(_) => "Entra ID",
DatabaseUrl::Static(_) => "",
};
if needs_token_refresh {
let pool2 = pool.clone();
let database_url2 = database_url.clone();
tokio::spawn(async move {
loop {
tokio::select! {
_ = killpill_rx.recv() => {
break;
}
_ = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
if !database_url2.needs_refresh().await {
continue;
}
let new_url = tokio::time::timeout(
std::time::Duration::from_secs(10),
get_database_url(),
)
.await;
match new_url {
Ok(Ok(new_url)) => {
match new_url.connect_options().await {
Ok(connect_options) => {
pool2.set_connect_options(connect_options);
tracing::info!("Refreshed IAM RDS URL successfully");
tracing::info!("Refreshed {label} URL successfully");
}
Err(e) => {
tracing::error!("Error getting IAM RDS connect options, retrying in 10s: {}", e);
tracing::error!(
"Error getting {label} connect options, retrying in 10s: {e}"
);
continue;
}
}
}
Ok(Err(e)) => {
tracing::error!("Error refreshing IAM RDS URL, trying again in 10s: {}", e);
tracing::error!(
"Error refreshing {label} URL, trying again in 10s: {e}"
);
continue;
}
Err(e) => {
tracing::error!("Timeout after 10s refreshing IAM RDS URL, trying again in 10 seconds: {}", e);
tracing::error!(
"Timeout after 10s refreshing {label} URL, trying again in 10s: {e}"
);
continue;
}
}
}
}
}
}
});
});
}
}
Ok(pool)

View File

@@ -1597,6 +1597,12 @@ async fn process_notify_event(
tracing::debug!("config changed but did not target this server/worker");
}
}
"restart_worker_group" => {
if worker_mode && payload == *WORKER_GROUP {
tracing::info!("Restart requested for worker group '{payload}'");
spawn_graceful_killpill(tx, db, 10, "worker group restart requested").await;
}
}
"notify_webhook_change" => {
tracing::info!(
"Webhook change detected, invalidating webhook cache: {}",

View File

@@ -38,7 +38,7 @@ account: workspace_id(char), id(int), expires_at(ts), refresh_token(char), clien
agent_token_blacklist: token(char), expires_at(ts), blacklisted_at(ts), blacklisted_by(char)
ai_agent_memory: workspace_id(char), conversation_id(uuid), step_id(char), messages(jsonb), created_at(ts), updated_at(ts)
alerts: id(int), alert_type(char), message(text), created_at(ts), acknowledged(bool), workspace_id(text), acknowledged_workspace(bool), resource(text)
app: id(bigint), workspace_id(char), path(char), summary(char), policy(jsonb), versions(bigint[]), extra_perms(jsonb), draft_only(bool), custom_path(text)
app: id(bigint), workspace_id(char), path(char), summary(char), policy(jsonb), versions(bigint[]), extra_perms(jsonb), draft_only(bool), custom_path(text), labels(text[])
FK: (workspace_id) -> workspace(id)
app_bundles: app_version_id(bigint), w_id(char), file_type(char), data(bytes)
app_script: id(bigint), app(bigint), hash(char(64)), lock(text), code(text), code_sha256(char(64))
@@ -72,9 +72,9 @@ deployment_metadata: workspace_id(char), path(char), script_hash(bigint), app_ve
draft: workspace_id(char), path(char), typ(draft_type), value(json), created_at(ts)
FK: (workspace_id) -> workspace(id)
email_to_igroup: email(char), igroup(char)
email_trigger: path(char), local_part(char), workspaced_local_part(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
email_trigger: path(char), local_part(char), workspaced_local_part(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
favorite: usr(char), workspace_id(char), path(char), favorite_kind(favorite_kind)
flow: workspace_id(char), path(char), summary(text), description(text), value(jsonb), edited_by(char), edited_at(ts), archived(bool), schema(json), extra_perms(jsonb), dependency_job(uuid), draft_only(bool), tag(char), ws_error_handler_muted(bool), dedicated_worker(bool), timeout(int), visible_to_runner_only(bool), concurrency_key(char), versions(bigint[]), on_behalf_of_email(text), lock_error_logs(text)
flow: workspace_id(char), path(char), summary(text), description(text), value(jsonb), edited_by(char), edited_at(ts), archived(bool), schema(json), extra_perms(jsonb), dependency_job(uuid), draft_only(bool), tag(char), ws_error_handler_muted(bool), dedicated_worker(bool), timeout(int), visible_to_runner_only(bool), concurrency_key(char), versions(bigint[]), on_behalf_of_email(text), lock_error_logs(text), labels(text[])
FK: (workspace_id) -> workspace(id)
flow_conversation: id(uuid), workspace_id(char), flow_path(char), title(char), created_at(ts), updated_at(ts), created_by(char)
FK: (workspace_id) -> workspace(id)
@@ -91,14 +91,14 @@ folder: name(char), workspace_id(char), display_name(char), owners(char), extra_
FK: (workspace_id) -> workspace(id)
folder_permission_history: id(bigint), workspace_id(char), folder_name(char), changed_by(char), changed_at(ts), change_type(char), affected(char)
FK: (workspace_id, folder_name) -> folder(workspace_id, name)
gcp_trigger: gcp_resource_path(char), topic_id(char), subscription_id(char), delivery_type(delivery_mode), delivery_config(jsonb), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), subscription_mode(gcp_subscription_mode), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), auto_acknowledge_msg(bool), ack_deadline(int), mode(trigger_mode)
gcp_trigger: gcp_resource_path(char), topic_id(char), subscription_id(char), delivery_type(delivery_mode), delivery_config(jsonb), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), subscription_mode(gcp_subscription_mode), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), auto_acknowledge_msg(bool), ack_deadline(int), mode(trigger_mode), labels(text[])
global_settings: name(char), value(jsonb), updated_at(ts)
group_: workspace_id(char), name(char), summary(text), extra_perms(jsonb)
FK: (workspace_id) -> workspace(id)
group_permission_history: id(bigint), workspace_id(char), group_name(char), changed_by(char), changed_at(ts), change_type(char), member_affected(char)
FK: (workspace_id, group_name) -> group_(workspace_id, name)
healthchecks: id(bigint), check_type(char), healthy(bool), created_at(ts)
http_trigger: path(char), route_path(char), route_path_key(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), authentication_method(authentication_method), http_method(http_method), static_asset_config(jsonb), is_static_website(bool), workspaced_route(bool), wrap_body(bool), raw_string(bool), authentication_resource_path(char), summary(char), description(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), request_type(request_type), mode(trigger_mode)
http_trigger: path(char), route_path(char), route_path_key(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), authentication_method(authentication_method), http_method(http_method), static_asset_config(jsonb), is_static_website(bool), workspaced_route(bool), wrap_body(bool), raw_string(bool), authentication_resource_path(char), summary(char), description(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), request_type(request_type), mode(trigger_mode), labels(text[])
input: id(uuid), workspace_id(char), runnable_id(char), runnable_type(runnable_type), name(text), args(jsonb), created_at(ts), created_by(char), is_public(bool)
FK: (workspace_id) -> workspace(id)
instance_group: name(char), summary(char), id(char), scim_display_name(char), external_id(char)
@@ -111,7 +111,7 @@ job_stats: workspace_id(char), job_id(uuid), metric_id(char), metric_name(char),
FK: (workspace_id) -> workspace(id)
kafka_pending_commits: id(bigint), workspace_id(char), kafka_trigger_path(char), topic(char), partition(int), offset(bigint), created_at(ts)
FK: (workspace_id, kafka_trigger_path) -> kafka_trigger(workspace_id, path)
kafka_trigger: path(char), kafka_resource_path(char), topics(char), group_id(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), filters(jsonb[]), auto_commit(bool)
kafka_trigger: path(char), kafka_resource_path(char), topics(char), group_id(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), filters(jsonb[]), auto_commit(bool), labels(text[])
log_file: hostname(char), log_ts(ts), ok_lines(bigint), err_lines(bigint), mode(log_mode), worker_group(char), file_path(char), json_fmt(bool)
magic_link: email(char), token(char), expiration(ts)
mcp_oauth_client: mcp_server_url(text), client_id(text), client_secret(text), client_secret_expires_at(ts), token_endpoint(text), created_at(ts)
@@ -121,10 +121,10 @@ mcp_oauth_server_client: client_id(char), client_name(char), redirect_uris(text[
mcp_oauth_server_code: code(char), client_id(char), user_email(char), workspace_id(char), scopes(text[]), redirect_uri(text), code_challenge(char), code_challenge_method(char), created_at(ts), expires_at(ts)
FK: (client_id) -> mcp_oauth_server_client(client_id)
metrics: id(char), value(jsonb), created_at(ts)
mqtt_trigger: mqtt_resource_path(char), subscribe_topics(jsonb[]), client_version(mqtt_client_version), v5_config(jsonb), v3_config(jsonb), client_id(char), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
mqtt_trigger: mqtt_resource_path(char), subscribe_topics(jsonb[]), client_version(mqtt_client_version), v5_config(jsonb), v3_config(jsonb), client_id(char), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
native_trigger: external_id(char), workspace_id(char), service_name(native_trigger_service), script_path(char), is_flow(bool), webhook_token_hash(char), service_config(jsonb), error(text), created_at(ts), updated_at(ts)
FK: (workspace_id) -> workspace(id)
nats_trigger: path(char), nats_resource_path(char), subjects(char), stream_name(char), consumer_name(char), use_jetstream(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
nats_trigger: path(char), nats_resource_path(char), subjects(char), stream_name(char), consumer_name(char), use_jetstream(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
FK: (workspace_id) -> workspace(id)
notify_event: id(bigint), channel(text), payload(text), created_at(ts)
otel_traces: trace_id(bytes), span_id(bytes), trace_state(text), parent_span_id(bytes), flags(int), name(text), kind(int), start_time_unix_nano(bigint), end_time_unix_nano(bigint), attributes(jsonb), dropped_attributes_count(int), events(jsonb), dropped_events_count(int), links(jsonb), dropped_links_count(int), status(jsonb)
@@ -133,23 +133,23 @@ parallel_monitor_lock: parent_flow_id(uuid), job_id(uuid), last_ping(ts)
password: email(char), password_hash(char), login_type(char), super_admin(bool), verified(bool), name(char), company(char), first_time_user(bool), username(char), devops(bool)
pending_user: email(char), created_at(ts), username(char)
pip_resolution_cache: hash(char), expiration(ts), lockfile(text)
postgres_trigger: path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), postgres_resource_path(char), error(text), server_id(char), last_server_ping(ts), replication_slot_name(char), publication_name(char), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
postgres_trigger: path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), postgres_resource_path(char), error(text), server_id(char), last_server_ping(ts), replication_slot_name(char), publication_name(char), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
FK: (workspace_id) -> workspace(id)
raw_app: path(char), version(int), workspace_id(char), summary(char), edited_at(ts), data(text), extra_perms(jsonb)
raw_app: path(char), version(int), workspace_id(char), summary(char), edited_at(ts), data(text), extra_perms(jsonb), labels(text[])
FK: (workspace_id) -> workspace(id)
resource: workspace_id(char), path(char), value(jsonb), description(text), resource_type(char), extra_perms(jsonb), edited_at(ts), created_by(char)
resource: workspace_id(char), path(char), value(jsonb), description(text), resource_type(char), extra_perms(jsonb), edited_at(ts), created_by(char), labels(text[])
FK: (workspace_id) -> workspace(id)
resource_type: workspace_id(char), name(char), schema(jsonb), description(text), edited_at(ts), created_by(char), format_extension(char), is_fileset(bool)
FK: (workspace_id) -> workspace(id)
resume_job: id(uuid), job(uuid), flow(uuid), created_at(ts), value(jsonb), approver(char), resume_id(int), approved(bool)
FK: (flow) -> v2_job_queue(id)
runnable_settings: hash(bigint), debouncing_settings(bigint), concurrency_settings(bigint)
schedule: workspace_id(char), path(char), edited_by(char), edited_at(ts), schedule(char), enabled(bool), script_path(char), args(jsonb), extra_perms(jsonb), is_flow(bool), email(char), error(text), timezone(char), on_failure(char), on_recovery(char), on_failure_times(int), on_failure_exact(bool), on_failure_extra_args(jsonb), on_recovery_times(int), on_recovery_extra_args(jsonb), ws_error_handler_muted(bool), retry(jsonb), summary(char), no_flow_overlap(bool), tag(char), paused_until(ts), on_success(char), on_success_extra_args(jsonb), cron_version(text), description(text), dynamic_skip(char)
schedule: workspace_id(char), path(char), edited_by(char), edited_at(ts), schedule(char), enabled(bool), script_path(char), args(jsonb), extra_perms(jsonb), is_flow(bool), email(char), error(text), timezone(char), on_failure(char), on_recovery(char), on_failure_times(int), on_failure_exact(bool), on_failure_extra_args(jsonb), on_recovery_times(int), on_recovery_extra_args(jsonb), ws_error_handler_muted(bool), retry(jsonb), summary(char), no_flow_overlap(bool), tag(char), paused_until(ts), on_success(char), on_success_extra_args(jsonb), cron_version(text), description(text), dynamic_skip(char), labels(text[])
FK: (workspace_id) -> workspace(id)
script: workspace_id(char), hash(bigint), path(char), parent_hashes(bigint[]), summary(text), description(text), content(text), created_by(char), created_at(ts), archived(bool), schema(json), deleted(bool), is_template(bool), extra_perms(jsonb), lock(text), lock_error_logs(text), language(script_lang), kind(script_kind), tag(char), draft_only(bool), envs(char), concurrent_limit(int), concurrency_time_window_s(int), cache_ttl(int), dedicated_worker(bool), ws_error_handler_muted(bool), priority(smallint), timeout(int), delete_after_use(bool), restart_unless_cancelled(bool), concurrency_key(char), visible_to_runner_only(bool), auto_kind(varchar), codebase(char), has_preprocessor(bool), on_behalf_of_email(text), schema_validation(bool), assets(jsonb), debounce_key(char), debounce_delay_s(int), cache_ignore_s3_path(bool), runnable_settings_handle(bigint)
script: workspace_id(char), hash(bigint), path(char), parent_hashes(bigint[]), summary(text), description(text), content(text), created_by(char), created_at(ts), archived(bool), schema(json), deleted(bool), is_template(bool), extra_perms(jsonb), lock(text), lock_error_logs(text), language(script_lang), kind(script_kind), tag(char), draft_only(bool), envs(char), concurrent_limit(int), concurrency_time_window_s(int), cache_ttl(int), dedicated_worker(bool), ws_error_handler_muted(bool), priority(smallint), timeout(int), delete_after_use(bool), restart_unless_cancelled(bool), concurrency_key(char), visible_to_runner_only(bool), auto_kind(varchar), codebase(char), has_preprocessor(bool), on_behalf_of_email(text), schema_validation(bool), assets(jsonb), debounce_key(char), debounce_delay_s(int), cache_ignore_s3_path(bool), runnable_settings_handle(bigint), labels(text[])
FK: (workspace_id) -> workspace(id)
skip_workspace_diff_tally: workspace_id(char), added_at(ts)
sqs_trigger: path(char), queue_url(char), aws_resource_path(char), message_attributes(text[]), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error(text), server_id(char), last_server_ping(ts), aws_auth_resource_type(aws_auth_resource_type), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
sqs_trigger: path(char), queue_url(char), aws_resource_path(char), message_attributes(text[]), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error(text), server_id(char), last_server_ping(ts), aws_auth_resource_type(aws_auth_resource_type), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
FK: (workspace_id) -> workspace(id)
trashbin: id(bigint), workspace_id(char), item_kind(char), item_path(char), item_data(jsonb), deleted_by(char), deleted_at(ts), expires_at(ts)
FK: (workspace_id) -> workspace(id)
@@ -173,9 +173,9 @@ v2_job_runtime: id(uuid), ping(ts), memory_peak(int)
FK: (id) -> v2_job_queue(id)
v2_job_status: id(uuid), flow_status(jsonb), flow_leaf_jobs(jsonb), workflow_as_code_status(jsonb)
FK: (id) -> v2_job_queue(id)
variable: workspace_id(char), path(char), value(char), is_secret(bool), description(char), extra_perms(jsonb), account(int), is_oauth(bool), expires_at(ts)
variable: workspace_id(char), path(char), value(char), is_secret(bool), description(char), extra_perms(jsonb), account(int), is_oauth(bool), expires_at(ts), labels(text[])
FK: (workspace_id) -> workspace(id)
websocket_trigger: path(char), url(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), filters(jsonb[]), initial_messages(jsonb[]), url_runnable_args(jsonb), can_return_message(bool), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), can_return_error_result(bool), mode(trigger_mode)
websocket_trigger: path(char), url(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), filters(jsonb[]), initial_messages(jsonb[]), url_runnable_args(jsonb), can_return_message(bool), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), can_return_error_result(bool), mode(trigger_mode), labels(text[])
windmill_migrations: name(text), created_at(ts)
worker_group_job_stats: hour(bigint), worker_group(text), script_lang(char), workspace_id(char), job_count(int), total_duration_ms(bigint)
FK: (workspace_id) -> workspace(id)

View File

@@ -429,6 +429,59 @@ export function main() {
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_bun_job_syntax_error_unclosed_bracket(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
// Reproduces the "Unexpected end of file at main.ts:0" error reported
// when a TS file has a missing closing bracket — Bun's bundler gives no
// useful location info.
let content = r#"
export async function main() {
if (true) {
return "hello";
// missing closing bracket for the function
"#
.to_owned();
let job = JobPayload::Code(RawCode {
hash: None,
content,
path: None,
language: ScriptLang::Bun,
lock: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
modules: None,
});
let completed = run_job_in_new_worker_until_complete(&db, false, job, port).await;
assert!(!completed.success);
let result = completed
.result
.as_ref()
.and_then(|v| v.get("error"))
.and_then(|v| v.get("message"))
.and_then(|v| v.as_str())
.unwrap_or("");
assert!(
result.contains("Unexpected end of file"),
"should contain bun parser error, got: {result}"
);
assert!(
result.contains("syntax error"),
"should contain helpful hint about syntax errors, got: {result}"
);
Ok(())
}
// ============================================================================
// Annotation Mode Tests
// ============================================================================
@@ -1013,8 +1066,8 @@ mod dedicated_worker_protocol {
let mut results = Vec::new();
for job_args in jobs {
// Protocol: exec:<script_path>:<json_args>
writeln!(stdin, "exec:{}:{}", TEST_SCRIPT_PATH, job_args.to_string()).unwrap();
// Protocol: execd:<json_args> (single-script, no path needed)
writeln!(stdin, "execd:{}", job_args.to_string()).unwrap();
stdin.flush().unwrap();
let mut response = String::new();
@@ -1600,8 +1653,6 @@ mod dedicated_worker_protocol_deno {
use windmill_test_utils::{parse_dedicated_worker_line, DedicatedWorkerResult};
use windmill_worker::{generate_deno_dedicated_worker_wrapper, DENO_PATH};
const TEST_SCRIPT_PATH: &str = "f/test/script";
fn run_deno_worker_test(
script: &str,
jobs: Vec<serde_json::Value>,
@@ -1651,7 +1702,7 @@ mod dedicated_worker_protocol_deno {
let mut results = Vec::new();
for job_args in jobs {
writeln!(stdin, "exec:{}:{}", TEST_SCRIPT_PATH, job_args.to_string()).unwrap();
writeln!(stdin, "execd:{}", job_args.to_string()).unwrap();
stdin.flush().unwrap();
loop {
@@ -1772,7 +1823,13 @@ export function main(msg: string): never {
let mut results = Vec::new();
for (cmd, args) in &commands {
writeln!(stdin, "{}:{}:{}", cmd, TEST_SCRIPT_PATH, args).unwrap();
// Single-script Deno wrapper uses execd:/execd_preprocess: (no path)
let direct_cmd = if *cmd == "exec_preprocess" {
"execd_preprocess"
} else {
"execd"
};
writeln!(stdin, "{}:{}", direct_cmd, args).unwrap();
stdin.flush().unwrap();
let expected_lines = if *cmd == "exec_preprocess" { 2 } else { 1 };

File diff suppressed because it is too large Load Diff

View File

@@ -450,6 +450,7 @@ def main():
on_behalf_of_email: None,
preserve_on_behalf_of: None,
ws_error_handler_muted: None,
labels: None,
})
.send()
.await
@@ -511,6 +512,7 @@ def main():
deployment_message: None,
custom_path: None,
preserve_on_behalf_of: None,
labels: None,
})
.send()
.await

View File

@@ -162,7 +162,7 @@ export async function main(path: string, email: string, job_id: string, is_flow:
priority: None,
apply_preprocessor: false,
concurrency_settings: ConcurrencySettings::default(),
debouncing_settings: DebouncingSettings::default(),
debouncing_settings: DebouncingSettings::default(), labels: None,
})
.run_until_complete(&db, false, server.addr.port())
.await;
@@ -285,7 +285,7 @@ async fn test_error_handler_muted_on_script(db: Pool<Postgres>) -> anyhow::Resul
priority: None,
apply_preprocessor: false,
concurrency_settings: ConcurrencySettings::default(),
debouncing_settings: DebouncingSettings::default(),
debouncing_settings: DebouncingSettings::default(), labels: None,
})
.run_until_complete(&db, false, server.addr.port())
.await;
@@ -380,7 +380,7 @@ async fn test_error_handler_not_triggered_on_success(db: Pool<Postgres>) -> anyh
priority: None,
apply_preprocessor: false,
concurrency_settings: ConcurrencySettings::default(),
debouncing_settings: DebouncingSettings::default(),
debouncing_settings: DebouncingSettings::default(), labels: None,
})
.run_until_complete(&db, false, server.addr.port())
.await;

View File

@@ -0,0 +1,599 @@
-- Fixtures for dedicated worker E2E tests
-- A simple Bun script for testing dedicated Script steps in flows
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'export function main(x: number) { return x * 2; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/dedicated_double', 300001, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- Flow with a single RawScript inline bun step (the "Script not found" bug case)
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_rawscript_flow',
'{3000000000000001}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000001,
'test-workspace',
'f/system/dedicated_rawscript_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow with a Script step referencing the external dedicated_double script
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_script_flow',
'{3000000000000002}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000002,
'test-workspace',
'f/system/dedicated_script_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- Flow with two inline RawScript steps (tests multi-step key uniqueness)
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_multi_step_flow',
'{3000000000000003}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x * 3; }","language":"bun","input_transforms":{"x":{"expr":"results.a","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000003,
'test-workspace',
'f/system/dedicated_multi_step_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x * 3; }","language":"bun","input_transforms":{"x":{"expr":"results.a","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Two scripts sharing a workspace dependency for runner group testing.
-- Both reference the same external dep "f/system/dedicated_double" via extra_package_json annotation.
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_script_a', 300010, 'bun', E'{}\n//bun.lock\n<empty>', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function main(x: number) { return x + 200; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_script_b', 300011, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- Flow with a Deno inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_deno_flow',
'{3000000000000005}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"deno","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000005,
'test-workspace',
'f/system/dedicated_deno_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"deno","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- Flow with a Python inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_python_flow',
'{3000000000000006}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"def main(x: int):\\n return x + 100","language":"python3","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000006,
'test-workspace',
'f/system/dedicated_python_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"def main(x: int):\\n return x + 100","language":"python3","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- Flow with a Bunnative (//native) inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_bunnative_flow',
'{3000000000000007}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//native\\nexport function main(x: number) { return x + 100; }","language":"bunnative","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000007,
'test-workspace',
'f/system/dedicated_bunnative_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//native\\nexport function main(x: number) { return x + 100; }","language":"bunnative","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow with a Bun + //nodejs annotation inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_nodejs_flow',
'{3000000000000008}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//nodejs\\nexport function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000008,
'test-workspace',
'f/system/dedicated_nodejs_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//nodejs\\nexport function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow with a squashed for-loop for testing flow runners.
-- The for-loop iterates over [1, 2, 3], each iteration runs a simple bun rawscript.
-- squash=true triggers spawn_flow_module_runners to create dedicated subprocesses.
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_flow_runners',
'{3000000000000004}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000004,
'test-workspace',
'f/system/dedicated_flow_runners',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- Two flows with conflicting step IDs (both have module "a") but different RawScript content.
-- Tests that runnable_path-based lookup correctly disambiguates them.
-- Flow A: x + 1000
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/conflict_flow_a',
'{3000000000000009}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000009,
'test-workspace',
'f/system/conflict_flow_a',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow B: x + 2000
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/conflict_flow_b',
'{3000000000000010}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 2000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000010,
'test-workspace',
'f/system/conflict_flow_b',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 2000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- A dedicated worker script with a preprocessor function.
-- preprocessor doubles x, main adds 100.
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'export function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/preprocess_script', 300030, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- Second workspace for cross-workspace isolation testing.
INSERT INTO workspace(id, name, owner) VALUES ('test-workspace-2', 'test-workspace-2', 'test-user');
INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
('test-workspace-2', 'test@windmill.dev', 'test-user', true, 'Admin');
INSERT INTO workspace_key(workspace_id, kind, key) VALUES
('test-workspace-2', 'cloud', 'test-key-2');
INSERT INTO workspace_settings (workspace_id) VALUES ('test-workspace-2');
INSERT INTO group_ (workspace_id, name, summary, extra_perms) VALUES
('test-workspace-2', 'all', 'All users', '{}');
-- Same path as dedicated_double but in workspace 2, returns x * 3 instead of x * 2.
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace-2',
'system',
E'export function main(x: number) { return x * 3; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/dedicated_double', 300040, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: flow Script step + standalone conflict
-- Flow references dedicated_double (also configured as standalone).
-- Standalone worker should handle both its own jobs and the flow's Script step jobs.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_conflict_standalone_flow',
'{3000000000000011}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000011,
'test-workspace',
'f/system/dedicated_conflict_standalone_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- ============================================================
-- Test: non-dedicated step inside dedicated flow
-- Flow with bun step (x + 10) then bash step (echo result * 2).
-- The bun step runs on dedicated worker; bash falls back to normal execution.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_mixed_lang_flow',
'{3000000000000012}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"results_a":{"expr":"results.a","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000012,
'test-workspace',
'f/system/dedicated_mixed_lang_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"results_a":{"expr":"results.a","type":"javascript"}}}}]}',
'system'
);
-- ============================================================
-- Test: non-dedicated step inside flow runners (squashed loop)
-- Squashed for-loop with a bash step. Bash can't spawn a flow runner,
-- so each iteration falls back to normal execution.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_flow_runners_bash',
'{3000000000000013}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"iter_value":{"expr":"flow_input.iter.value","type":"javascript"}}}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000013,
'test-workspace',
'f/system/dedicated_flow_runners_bash',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"iter_value":{"expr":"flow_input.iter.value","type":"javascript"}}}}]}}]}',
'system'
);
-- ============================================================
-- Test: Python runner group
-- Two Python scripts sharing a workspace dependency annotation.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/dedicated_double\ndef main(x: int):\n return x + 100',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_script_a', 300050, 'python3', '', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/dedicated_double\ndef main(x: int):\n return x + 200',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_script_b', 300051, 'python3', '', true);
-- ============================================================
-- Test: preprocessor in runner group
-- Two bun scripts sharing a workspace dep, one has a preprocessor.
-- Tests exec_preprocess:{path}:{args} protocol in runner groups.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_preprocess_script', 300052, 'bun', E'{}\n//bun.lock\n<empty>', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function main(x: number) { return x + 300; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_preprocess_other', 300053, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: flow with BranchOne
-- Flow with branchone: condition true → branch (x + 100), default → (x + 200).
-- Tests recursive module traversal for spawning dedicated workers.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_branch_flow',
'{3000000000000014}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchone","branches":[{"expr":"flow_input.x > 10","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000014,
'test-workspace',
'f/system/dedicated_branch_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchone","branches":[{"expr":"flow_input.x > 10","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- ============================================================
-- Test: Python standalone preprocessor
-- Python script with preprocessor function. Tests execd_preprocess: protocol.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'def preprocessor(x: int):\n return {"x": x * 2}\n\ndef main(x: int):\n return x + 100',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_preprocess_script', 300054, 'python3', '', true);
-- ============================================================
-- Test: Deno standalone preprocessor
-- Deno script with preprocessor function. Tests execd_preprocess: protocol.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'export function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/deno_preprocess_script', 300055, 'deno', '', true);
-- ============================================================
-- Test: Python runner group preprocessor
-- Two Python scripts sharing a workspace dep, one has a preprocessor.
-- Tests exec_preprocess:{path}:{args} protocol for Python runner groups.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/py_preprocess_script\ndef preprocessor(x: int):\n return {"x": x * 2}\n\ndef main(x: int):\n return x + 100',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_preprocess_a', 300056, 'python3', '', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/py_preprocess_script\ndef main(x: int):\n return x + 300',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_preprocess_b', 300057, 'python3', '', true);
-- ============================================================
-- Test: Bunnative standalone preprocessor
-- Bunnative script with preprocessor function. Tests V8 isolate preprocessing.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'//native\nexport function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/bunnative_preprocess_script', 300058, 'bunnative', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: Bun dedicated worker with relative imports
-- Helper script at f/system/dedicated_helper (returns x * 10).
-- Dedicated script imports from it using a relative path.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES (
'test-workspace',
'system',
E'export function helper(x: number) { return x * 10; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
'', '',
'f/system/dedicated_helper', 300060, 'bun', E'{}\n//bun.lock\n<empty>');
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'import { helper } from "./dedicated_helper.ts";\n\nexport function main(x: number) { return helper(x) + 1; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/dedicated_with_import', 300061, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: Python dedicated worker with relative imports
-- Helper script at f/system/py_dedicated_helper (returns x * 10).
-- Dedicated script imports from it using a relative path.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES (
'test-workspace',
'system',
E'def helper(x: int):\n return x * 10',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
'', '',
'f/system/py_dedicated_helper', 300062, 'python3', '');
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'from .py_dedicated_helper import helper\n\ndef main(x: int):\n return helper(x) + 1',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_dedicated_with_import', 300063, 'python3', '', true);
-- ============================================================
-- Test: non-squashed for-loop in dedicated flow
-- For-loop iterates over [1, 2, 3], inner bun step returns iter.value * 10.
-- NOT squashed, so inner steps use the dedicated worker map (not flow runners).
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_forloop_flow',
'{3000000000000015}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000015,
'test-workspace',
'f/system/dedicated_forloop_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- ============================================================
-- Test: non-simple for-loop in dedicated flow (multi-step)
-- For-loop iterates over [1, 2, 3], two steps: step b (iter.value + 1), step c (results.b * 10).
-- Two steps makes is_simple_modules false, so inner steps run as separate jobs.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_forloop_multi_step_flow',
'{3000000000000019}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value + 1; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"c","value":{"type":"rawscript","content":"export function main(prev: number) { return prev * 10; }","language":"bun","input_transforms":{"prev":{"expr":"results.b","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000019,
'test-workspace',
'f/system/dedicated_forloop_multi_step_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value + 1; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"c","value":{"type":"rawscript","content":"export function main(prev: number) { return prev * 10; }","language":"bun","input_transforms":{"prev":{"expr":"results.b","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- ============================================================
-- Test: while-loop in dedicated flow
-- While-loop with an inner bun step that returns x + 1.
-- Early stop breaks when result >= 3.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_whileloop_flow',
'{3000000000000016}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"whileloopflow","skip_failures":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(n: number) { return n + 1; }","language":"bun","input_transforms":{"n":{"expr":"results.b ?? flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"},"stop_after_if":{"expr":"result >= 3","skip_if_stopped":false}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000016,
'test-workspace',
'f/system/dedicated_whileloop_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"whileloopflow","skip_failures":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(n: number) { return n + 1; }","language":"bun","input_transforms":{"n":{"expr":"results.b ?? flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"},"stop_after_if":{"expr":"result >= 3","skip_if_stopped":false}}]}}]}',
'system'
);
-- ============================================================
-- Test: branchall in dedicated flow
-- BranchAll with 2 parallel branches, each with a bun step.
-- Branch 0: x + 100, Branch 1: x + 200.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_branchall_flow',
'{3000000000000017}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchall","parallel":true,"branches":[{"expr":"true","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]},{"expr":"true","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000017,
'test-workspace',
'f/system/dedicated_branchall_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchall","parallel":true,"branches":[{"expr":"true","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]},{"expr":"true","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}]}}]}',
'system'
);
-- ============================================================
-- Test: nested branch inside loop in dedicated flow
-- For-loop [1,2] with inner branchone: if iter.value > 1 → x + 100, else → x + 200.
-- Tests deeply nested dispatch (forloop-N/branchone-0/step_id).
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_nested_flow',
'{3000000000000018}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"branchone","branches":[{"expr":"flow_input.iter.value > 1","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 100; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"d","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 200; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000018,
'test-workspace',
'f/system/dedicated_nested_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"branchone","branches":[{"expr":"flow_input.iter.value > 1","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 100; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"d","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 200; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}}]}',
'system'
);

View File

@@ -240,7 +240,10 @@ async fn test_from_db_worker_config_prefix_stripping(db: Pool<Postgres>) {
config.worker_configs.contains_key("my_group_name"),
"worker__ prefix should be stripped"
);
assert_eq!(config.worker_configs["my_group_name"].extra["cache_clear"], serde_json::json!(5));
assert_eq!(
config.worker_configs["my_group_name"].extra["cache_clear"],
serde_json::json!(5)
);
}
#[sqlx::test(fixtures("base"))]
@@ -400,12 +403,11 @@ async fn test_apply_settings_diff_complex_json(db: Pool<Postgres>) {
#[sqlx::test(fixtures("base"))]
async fn test_apply_settings_diff_delete_nonexistent_is_noop(db: Pool<Postgres>) {
let diff =
SettingsDiff {
upserts: BTreeMap::new(),
deletes: vec!["does_not_exist".to_string()],
..Default::default()
};
let diff = SettingsDiff {
upserts: BTreeMap::new(),
deletes: vec!["does_not_exist".to_string()],
..Default::default()
};
// Should not error
apply_settings_diff(&db, &diff).await.unwrap();
@@ -657,11 +659,8 @@ async fn test_roundtrip_to_settings_map_from_db_consistency(db: Pool<Postgres>)
};
let map = original.to_settings_map();
let diff = SettingsDiff {
upserts: map.into_iter().collect(),
deletes: vec![],
..Default::default()
};
let diff =
SettingsDiff { upserts: map.into_iter().collect(), deletes: vec![], ..Default::default() };
apply_settings_diff(&db, &diff).await.unwrap();
@@ -866,7 +865,10 @@ async fn test_full_config_roundtrip(db: Pool<Postgres>) {
assert_eq!(otel.tracing_enabled, Some(true));
assert_eq!(config.worker_configs.len(), 2);
assert_eq!(config.worker_configs["default"].extra["cache_clear"], serde_json::json!(7));
assert_eq!(
config.worker_configs["default"].extra["cache_clear"],
serde_json::json!(7)
);
let gpu_auto = config.worker_configs["gpu"].autoscaling.as_ref().unwrap();
assert!(gpu_auto.enabled);
assert_eq!(gpu_auto.min_workers, Some(0));
@@ -1006,3 +1008,146 @@ async fn test_replace_mode_protects_settings_in_integration(db: Pool<Postgres>)
Some(serde_json::json!("yes"))
);
}
// ========================================================================
// jwt_secret and rsa_keys declarative roundtrip
// ========================================================================
#[sqlx::test(fixtures("base"))]
async fn test_jwt_secret_roundtrip_as_string_or_secret_ref(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
// Simulate what the operator does: parse a GlobalSettings with jwt_secret
// as a resolved StringOrSecretRef::Literal, write to DB, read back.
let settings = windmill_common::instance_config::GlobalSettings {
jwt_secret: Some(
windmill_common::instance_config::StringOrSecretRef::Literal(
"my-jwt-secret-from-k8s".to_string(),
),
),
..Default::default()
};
let map = settings.to_settings_map();
// The serialized form should be a plain JSON string (not an object)
assert_eq!(
map["jwt_secret"],
serde_json::json!("my-jwt-secret-from-k8s")
);
let diff =
SettingsDiff { upserts: map.into_iter().collect(), deletes: vec![], ..Default::default() };
apply_settings_diff(&db, &diff).await.unwrap();
// Read back from DB — jwt_secret should survive the roundtrip
let config = InstanceConfig::from_db(&db).await.unwrap();
assert_eq!(
config
.global_settings
.jwt_secret
.as_ref()
.and_then(|v| v.as_literal()),
Some("my-jwt-secret-from-k8s")
);
// Verify the raw DB value is a plain string (not wrapped in an object)
let raw = get_global_setting(&db, "jwt_secret").await.unwrap();
assert!(
raw.is_string(),
"jwt_secret in DB should be a plain JSON string"
);
assert_eq!(raw.as_str().unwrap(), "my-jwt-secret-from-k8s");
}
#[sqlx::test(fixtures("base"))]
async fn test_rsa_keys_roundtrip_via_extra(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
// rsa_keys is not a typed field — it flows through GlobalSettings.extra.
// Simulate a resolved secretKeyRef: the operator resolves the ref and
// writes the plain value to extra before syncing to DB.
let json_str = r#"{
"rsa_keys": {
"private_key": "-----BEGIN RSA PRIVATE KEY-----\ntest-key-data\n-----END RSA PRIVATE KEY-----"
}
}"#;
let settings: windmill_common::instance_config::GlobalSettings =
serde_json::from_str(json_str).unwrap();
// rsa_keys should land in extra
assert!(settings.extra.contains_key("rsa_keys"));
let map = settings.to_settings_map();
let diff =
SettingsDiff { upserts: map.into_iter().collect(), deletes: vec![], ..Default::default() };
apply_settings_diff(&db, &diff).await.unwrap();
// Read back from DB
let config = InstanceConfig::from_db(&db).await.unwrap();
assert_eq!(
config.global_settings.extra["rsa_keys"]["private_key"],
"-----BEGIN RSA PRIVATE KEY-----\ntest-key-data\n-----END RSA PRIVATE KEY-----"
);
// Verify the raw DB value is a JSON object with private_key
let raw = get_global_setting(&db, "rsa_keys").await.unwrap();
assert!(raw.is_object());
assert_eq!(
raw["private_key"].as_str().unwrap(),
"-----BEGIN RSA PRIVATE KEY-----\ntest-key-data\n-----END RSA PRIVATE KEY-----"
);
}
#[sqlx::test(fixtures("base"))]
async fn test_replace_mode_protects_jwt_secret_and_rsa_keys(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
// Seed jwt_secret and rsa_keys (both are PROTECTED_SETTINGS)
insert_global_setting(&db, "jwt_secret", serde_json::json!("existing-secret")).await;
insert_global_setting(
&db,
"rsa_keys",
serde_json::json!({"private_key": "existing-rsa-key"}),
)
.await;
insert_global_setting(&db, "normal_setting", serde_json::json!("will-go")).await;
let config = InstanceConfig::from_db(&db).await.unwrap();
let current_map = config.global_settings.to_settings_map();
// Desired state: only base_url — jwt_secret and rsa_keys should survive
let mut desired_map = BTreeMap::new();
desired_map.insert(
"base_url".to_string(),
serde_json::json!("https://example.com"),
);
let diff = diff_global_settings(&current_map, &desired_map, ApplyMode::Replace);
assert!(
!diff.deletes.contains(&"jwt_secret".to_string()),
"jwt_secret is protected from deletion"
);
assert!(
!diff.deletes.contains(&"rsa_keys".to_string()),
"rsa_keys is protected from deletion"
);
assert!(
diff.deletes.contains(&"normal_setting".to_string()),
"normal_setting should be deleted"
);
apply_settings_diff(&db, &diff).await.unwrap();
// Both protected settings survive
assert_eq!(
get_global_setting(&db, "jwt_secret").await,
Some(serde_json::json!("existing-secret"))
);
assert_eq!(
get_global_setting(&db, "rsa_keys").await,
Some(serde_json::json!({"private_key": "existing-rsa-key"}))
);
assert!(get_global_setting(&db, "normal_setting").await.is_none());
}

View File

@@ -49,7 +49,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(),
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
@@ -89,7 +89,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(),
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
})
.run_until_complete_with(db, false, port, |id| async move {
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
@@ -424,7 +424,7 @@ mod job_payload {
path: "f/system/hello_with_nodes_flow".to_string(),
dedicated_worker: None,
apply_preprocessor: false,
version: 1443253234253454,
version: 1443253234253454, labels: None,
})
.run_until_complete(&db, false, port)
.await
@@ -473,7 +473,7 @@ mod job_payload {
path: "f/system/hello_with_preprocessor".to_string(),
dedicated_worker: None,
apply_preprocessor: true,
version: 1443253234253456,
version: 1443253234253456, labels: None,
})
.run_until_complete_with(db, false, port, |id| async move {
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
@@ -543,7 +543,7 @@ mod job_payload {
path: "f/system/hello_with_nodes_flow".to_string(),
dedicated_worker: None,
apply_preprocessor: true,
version: 1443253234253454,
version: 1443253234253454, labels: None,
})
.run_until_complete(&db, false, port)
.await
@@ -789,7 +789,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(),
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -839,7 +839,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(),
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -889,7 +889,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(),
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -939,7 +939,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(),
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -991,7 +991,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(),
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))

View File

@@ -64,8 +64,8 @@ async fn test_list_jobs_without_include_args(db: Pool<Postgres>) -> anyhow::Resu
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -121,8 +121,8 @@ async fn test_list_jobs_with_include_args(db: Pool<Postgres>) -> anyhow::Result<
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -192,8 +192,8 @@ async fn test_list_jobs_completed_with_include_args(db: Pool<Postgres>) -> anyho
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -265,8 +265,8 @@ async fn test_list_jobs_mixed_queue_and_completed(db: Pool<Postgres>) -> anyhow:
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -286,8 +286,8 @@ async fn test_list_jobs_mixed_queue_and_completed(db: Pool<Postgres>) -> anyhow:
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -349,7 +349,9 @@ async fn test_list_jobs_mixed_queue_and_completed(db: Pool<Postgres>) -> anyhow:
/// Test list_jobs with multiple queued jobs and include_args
#[sqlx::test(fixtures("base"))]
async fn test_list_jobs_multiple_queued_with_include_args(db: Pool<Postgres>) -> anyhow::Result<()> {
async fn test_list_jobs_multiple_queued_with_include_args(
db: Pool<Postgres>,
) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
@@ -369,8 +371,8 @@ async fn test_list_jobs_multiple_queued_with_include_args(db: Pool<Postgres>) ->
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -387,8 +389,8 @@ async fn test_list_jobs_multiple_queued_with_include_args(db: Pool<Postgres>) ->
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -411,9 +413,13 @@ async fn test_list_jobs_multiple_queued_with_include_args(db: Pool<Postgres>) ->
let jobs: Vec<ListJobsResponse> = response.json().await?;
// Find both jobs
let job1 = jobs.iter().find(|j| j.id == job1_id.to_string())
let job1 = jobs
.iter()
.find(|j| j.id == job1_id.to_string())
.expect("should find job1");
let job2 = jobs.iter().find(|j| j.id == job2_id.to_string())
let job2 = jobs
.iter()
.find(|j| j.id == job2_id.to_string())
.expect("should find job2");
// Both should have args
@@ -461,8 +467,8 @@ async fn test_queue_list_without_include_args(db: Pool<Postgres>) -> anyhow::Res
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -480,10 +486,7 @@ async fn test_queue_list_without_include_args(db: Pool<Postgres>) -> anyhow::Res
.send()
.await?;
assert!(
response.status().is_success(),
"queue/list should succeed"
);
assert!(response.status().is_success(), "queue/list should succeed");
let jobs: Vec<QueueJobResponse> = response.json().await?;
@@ -524,8 +527,8 @@ async fn test_queue_list_with_include_args(db: Pool<Postgres>) -> anyhow::Result
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -594,8 +597,8 @@ async fn test_queue_list_multiple_jobs_with_include_args(db: Pool<Postgres>) ->
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -612,8 +615,8 @@ async fn test_queue_list_multiple_jobs_with_include_args(db: Pool<Postgres>) ->
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -631,10 +634,7 @@ async fn test_queue_list_multiple_jobs_with_include_args(db: Pool<Postgres>) ->
.send()
.await?;
assert!(
response.status().is_success(),
"queue/list should succeed"
);
assert!(response.status().is_success(), "queue/list should succeed");
let jobs: Vec<QueueJobResponse> = response.json().await?;
@@ -694,8 +694,8 @@ async fn test_completed_list_without_include_args(db: Pool<Postgres>) -> anyhow:
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -760,8 +760,8 @@ async fn test_completed_list_with_include_args(db: Pool<Postgres>) -> anyhow::Re
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -835,8 +835,8 @@ async fn test_completed_list_multiple_jobs_with_include_args(
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -856,8 +856,8 @@ async fn test_completed_list_multiple_jobs_with_include_args(
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -912,3 +912,273 @@ async fn test_completed_list_multiple_jobs_with_include_args(
Ok(())
}
// =============================================================================
// Labels integration tests
// =============================================================================
#[sqlx::test(fixtures("base"))]
async fn test_job_labels_propagated_at_push_time(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Push a script job with labels
let job_id = RunJob::from(JobPayload::ScriptHash {
hash: windmill_common::scripts::ScriptHash(0),
path: "u/admin/test_labels_script".to_string(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
language: ScriptLang::Python3,
priority: None,
apply_preprocessor: false,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
labels: Some(vec!["prod".to_string(), "deploy".to_string()]),
})
.push(&db)
.await;
// Verify labels in queue listing
let response = client
.client()
.get(format!("{}/w/test-workspace/jobs/list", client.baseurl()))
.send()
.await?;
assert!(response.status().is_success());
let jobs: Vec<serde_json::Value> = response.json().await?;
let job = jobs
.iter()
.find(|j| j["id"].as_str() == Some(&job_id.to_string()))
.expect("should find job");
let labels = job["labels"].as_array().expect("labels should be an array");
assert!(labels.contains(&json!("prod")));
assert!(labels.contains(&json!("deploy")));
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_job_without_labels_has_no_labels_field(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Push a job without labels
let job_id = RunJob::from(JobPayload::Code(RawCode {
hash: None,
content: "def main(): return 1".to_string(),
path: None,
language: ScriptLang::Python3,
lock: None,
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
.push(&db)
.await;
let response = client
.client()
.get(format!("{}/w/test-workspace/jobs/list", client.baseurl()))
.send()
.await?;
assert!(response.status().is_success());
let jobs: Vec<serde_json::Value> = response.json().await?;
let job = jobs
.iter()
.find(|j| j["id"].as_str() == Some(&job_id.to_string()))
.expect("should find job");
// Labels should be null/missing for jobs without labels
assert!(
job.get("labels").is_none() || job["labels"].is_null(),
"job without labels should not have labels field"
);
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_job_label_filter(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Push two jobs with different labels, then complete them via SQL
// Label filtering only works on completed jobs
let job_prod_id = RunJob::from(JobPayload::ScriptHash {
hash: windmill_common::scripts::ScriptHash(0),
path: "u/admin/prod_script".to_string(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
language: ScriptLang::Bun,
priority: None,
apply_preprocessor: false,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
labels: Some(vec!["prod".to_string()]),
})
.push(&db)
.await;
let job_staging_id = RunJob::from(JobPayload::ScriptHash {
hash: windmill_common::scripts::ScriptHash(0),
path: "u/admin/staging_script".to_string(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
language: ScriptLang::Bun,
priority: None,
apply_preprocessor: false,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
labels: Some(vec!["staging".to_string()]),
})
.push(&db)
.await;
// Complete both jobs directly via SQL so label filter can find them
for job_id in &[job_prod_id, job_staging_id] {
sqlx::query(
"INSERT INTO v2_job_completed (workspace_id, id, result, status, duration_ms) VALUES ('test-workspace', $1, '{}'::jsonb, 'success', 0)",
)
.bind(job_id)
.execute(&db)
.await?;
}
// Filter by label=prod
let response = client
.client()
.get(format!(
"{}/w/test-workspace/jobs/list?label=prod",
client.baseurl()
))
.send()
.await?;
assert!(response.status().is_success());
let jobs: Vec<serde_json::Value> = response.json().await?;
// Should find the prod job
assert!(
jobs.iter()
.any(|j| j["id"].as_str() == Some(&job_prod_id.to_string())),
"prod job should appear in label=prod filter"
);
// Should NOT find the staging job
assert!(
!jobs
.iter()
.any(|j| j["id"].as_str() == Some(&job_staging_id.to_string())),
"staging job should not appear in label=prod filter"
);
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_wm_labels_from_result_merged_with_static_labels(
db: Pool<Postgres>,
) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Use Code(RawCode) to run a Bun script that returns wm_labels,
// then set static labels on the job row before execution
let job = RunJob::from(JobPayload::Code(RawCode {
hash: None,
content: r#"export async function main() { return { wm_labels: ["runtime-label"] }; }"#
.to_string(),
path: None,
language: ScriptLang::Bun,
lock: None,
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}));
let completed = job
.run_until_complete_with(&db, false, port, |uuid| {
let db = db.clone();
async move {
// Set static labels before the worker picks up the job
sqlx::query(
"UPDATE v2_job SET labels = ARRAY['static-label']::text[] WHERE id = $1",
)
.bind(uuid)
.execute(&db)
.await
.expect("should set labels");
}
})
.await;
// Fetch the job via API and check labels
let response = client
.client()
.get(format!(
"{}/w/test-workspace/jobs_u/get/{}",
client.baseurl(),
completed.id
))
.send()
.await?;
assert!(response.status().is_success());
let job: serde_json::Value = response.json().await?;
let labels = job["labels"].as_array().expect("labels should be an array");
// Should contain both the static label and runtime label from wm_labels
assert!(
labels.contains(&json!("static-label")),
"should contain static label set at push time, got: {:?}",
labels
);
assert!(
labels.contains(&json!("runtime-label")),
"should contain runtime label from wm_labels in result, got: {:?}",
labels
);
Ok(())
}

View File

@@ -445,4 +445,89 @@ mod tests {
Some(serde_json::json!("value"))
);
}
// ========================================================================
// jwt_secret and rsa_keys via sync_global_settings
// ========================================================================
#[sqlx::test(fixtures("base"))]
async fn test_sync_jwt_secret_via_settings_map(db: Pool<Postgres>) {
// Simulate the full operator pipeline: parse GlobalSettings with a
// resolved jwt_secret (StringOrSecretRef::Literal), convert to
// settings map, and sync to DB.
let settings = windmill_common::instance_config::GlobalSettings {
jwt_secret: Some(
windmill_common::instance_config::StringOrSecretRef::Literal(
"resolved-jwt-value".to_string(),
),
),
..Default::default()
};
let map = settings.to_settings_map();
windmill_operator::db_sync::sync_global_settings(&db, &map)
.await
.expect("sync should succeed");
let stored = get_global_setting(&db, "jwt_secret")
.await
.expect("jwt_secret should exist");
assert_eq!(stored, serde_json::json!("resolved-jwt-value"));
}
#[sqlx::test(fixtures("base"))]
async fn test_sync_rsa_keys_via_settings_map(db: Pool<Postgres>) {
// rsa_keys flows through GlobalSettings.extra as opaque JSON.
// After operator resolves secretKeyRef, the value is a plain JSON
// object that gets synced to DB.
let json_str = r#"{
"rsa_keys": {
"private_key": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----"
}
}"#;
let settings: windmill_common::instance_config::GlobalSettings =
serde_json::from_str(json_str).unwrap();
let map = settings.to_settings_map();
windmill_operator::db_sync::sync_global_settings(&db, &map)
.await
.expect("sync should succeed");
let stored = get_global_setting(&db, "rsa_keys")
.await
.expect("rsa_keys should exist");
assert_eq!(
stored["private_key"],
"-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----"
);
}
#[sqlx::test(fixtures("base"))]
async fn test_sync_protects_jwt_secret_and_rsa_keys(db: Pool<Postgres>) {
// Pre-populate both protected settings
insert_global_setting(&db, "jwt_secret", serde_json::json!("original-jwt")).await;
insert_global_setting(
&db,
"rsa_keys",
serde_json::json!({"private_key": "original-rsa"}),
)
.await;
// Sync with empty desired — protected keys should survive
let desired = BTreeMap::new();
windmill_operator::db_sync::sync_global_settings(&db, &desired)
.await
.expect("sync should succeed");
assert_eq!(
get_global_setting(&db, "jwt_secret").await,
Some(serde_json::json!("original-jwt")),
"jwt_secret is protected and should survive empty sync"
);
assert_eq!(
get_global_setting(&db, "rsa_keys").await,
Some(serde_json::json!({"private_key": "original-rsa"})),
"rsa_keys is protected and should survive empty sync"
);
}
}

View File

@@ -227,6 +227,8 @@ mod dedicated_worker_protocol_python {
enum ProtocolCmd {
Exec { path: String, args: serde_json::Value },
ExecPreprocess { path: String, args: serde_json::Value },
Execd { args: serde_json::Value },
ExecdPreprocess { args: serde_json::Value },
}
/// Run a Python worker test with raw protocol commands
@@ -265,13 +267,15 @@ mod dedicated_worker_protocol_python {
ProtocolCmd::ExecPreprocess { path, args } => {
format!("exec_preprocess:{}:{}", path, args)
}
ProtocolCmd::Execd { args } => format!("execd:{}", args),
ProtocolCmd::ExecdPreprocess { args } => format!("execd_preprocess:{}", args),
};
writeln!(stdin, "{}", line).unwrap();
stdin.flush().unwrap();
let expected_lines = match cmd {
ProtocolCmd::ExecPreprocess { .. } => 2,
ProtocolCmd::Exec { .. } => 1,
ProtocolCmd::ExecPreprocess { .. } | ProtocolCmd::ExecdPreprocess { .. } => 2,
ProtocolCmd::Exec { .. } | ProtocolCmd::Execd { .. } => 1,
};
for _ in 0..expected_lines {
@@ -374,6 +378,93 @@ def main(x: int):
);
}
// ==================== execd / execd_preprocess Tests ====================
#[test]
fn test_python_execd_single_script() {
let results = run_py_raw_protocol_test(
&[(
"f/test/add",
"def main(a: int, b: int):\n return a + b\n",
)],
vec![ProtocolCmd::Execd { args: serde_json::json!({"a": 3, "b": 4}) }],
);
assert_eq!(results.len(), 1);
assert_eq!(
results[0],
DedicatedWorkerResult::Success(serde_json::json!(7))
);
}
#[test]
fn test_python_execd_preprocess() {
let script = r#"
def preprocessor(x: int):
return {"x": x * 10}
def main(x: int):
return x + 1
"#;
let results = run_py_raw_protocol_test(
&[("f/test/pre", script)],
vec![ProtocolCmd::ExecdPreprocess { args: serde_json::json!({"x": 5}) }],
);
assert_eq!(results.len(), 2);
assert_eq!(
results[0],
DedicatedWorkerResult::PreprocessedArgs(serde_json::json!({"x": 50}))
);
// main(50) => 51
assert_eq!(
results[1],
DedicatedWorkerResult::Success(serde_json::json!(51))
);
}
#[test]
fn test_python_execd_preprocess_missing_preprocessor() {
let script = "def main(x: int):\n return x\n";
let results = run_py_raw_protocol_test(
&[("f/test/nopre", script)],
vec![ProtocolCmd::ExecdPreprocess { args: serde_json::json!({"x": 5}) }],
);
assert_eq!(results.len(), 1);
assert!(matches!(results[0], DedicatedWorkerResult::Error(_)));
}
#[test]
fn test_python_execd_preprocess_then_execd() {
let script = r#"
def preprocessor(x: int):
return {"x": x * 2}
def main(x: int):
return x + 100
"#;
let results = run_py_raw_protocol_test(
&[("f/test/mixed", script)],
vec![
ProtocolCmd::ExecdPreprocess { args: serde_json::json!({"x": 5}) },
ProtocolCmd::Execd { args: serde_json::json!({"x": 7}) },
],
);
// preprocess: preprocessor(5) => {"x":10}, main(10) => 110
// execd: main(7) => 107
assert_eq!(results.len(), 3);
assert_eq!(
results[0],
DedicatedWorkerResult::PreprocessedArgs(serde_json::json!({"x": 10}))
);
assert_eq!(
results[1],
DedicatedWorkerResult::Success(serde_json::json!(110))
);
assert_eq!(
results[2],
DedicatedWorkerResult::Success(serde_json::json!(107))
);
}
// ==================== Argument Transformation Tests ====================
#[test]

View File

@@ -101,7 +101,9 @@ mod relock_skip {
before
}
#[cfg(feature = "python")]
// Requires `private` feature for the dependency job concurrency limit that prevents
// race conditions between concurrent dep jobs for the same flow/app.
#[cfg(all(feature = "python", feature = "private"))]
#[sqlx::test(fixtures("base", "dependency_map"))]
async fn relock_skip_on_script_redeployment(db: Pool<Postgres>) -> anyhow::Result<()> {
std::env::set_var("DEPENDENCY_JOB_DEBOUNCE_DELAY", "0");
@@ -128,8 +130,9 @@ def main():
.await
.unwrap();
// leaf_1(1) + branch(1) + root_script(2: leaf_1+branch) + root_flow(2) + root_app(2) = 8 jobs
wait_for_jobs(&mut completed, 8).await;
// leaf_1(1) + branch(1) + root_script(1-2) + root_flow(1-2) + root_app(1-2) = 5-8 jobs
// With debouncing (private feature), duplicate dep jobs from branch cascade may be coalesced.
wait_for_jobs_ge(&mut completed, 5).await;
let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
@@ -236,7 +239,9 @@ def main():
Ok(())
}
#[cfg(feature = "python")]
// Requires `private` feature for the dependency job concurrency limit that prevents
// race conditions between concurrent dep jobs for the same flow/app.
#[cfg(all(feature = "python", feature = "private"))]
#[sqlx::test(fixtures("base", "dependency_map"))]
async fn relock_skip_on_workspace_deps_redeployment(db: Pool<Postgres>) -> anyhow::Result<()> {
use windmill_common::scripts::ScriptLang;

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