* feat: add script module mode with folder model for Bun and Python
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add missing modules field to RawCode in bun_executor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* sqlx
* feat: enrich WAC templates with checkpoint and replay semantics
Add prominent comments explaining that all computation must happen
inside task/step/taskScript or it will be replayed on resume/retry.
Clarify that waitForApproval does not hold a worker and that
approve/reject URLs are available in the timeline step details.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(cli): script module sync idempotency, per-module hash tracking, and preview support
- Fix pull→push idempotency: use `??` instead of `||` for module lock
field so empty strings are preserved (matches API's `lock: ""`)
- Add per-module hash tracking in wmill-lock.yaml following the flow
inline script pattern (SCRIPT_TOP_HASH + per-module subpath hashes)
- Selective module lock regeneration: only regenerate locks for modules
whose content actually changed, not all modules
- Use unfiltered rawWorkspaceDependencies for module hashes to match
what updateModuleLocks passes to fetchScriptLock
- Show changed module names in stale script output for clarity
- Add module support to `script preview` command: read modules from
__mod/ folder and pass them in the preview API request
- Add preview tests for taskScript pattern (flat and folder layout)
- Update test assertion for module stale detection output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(frontend): WAC UI improvements — reorder templates, module tab rename, import consolidation
- Reorder WAC template buttons: TypeScript before Python in
ScriptBuilder, CreateActionsScript, and CreateActionsFlow
- Remove dropdown items from +Script button (simplify to direct link)
- Move "Import Workflow-as-Code" to +Flow dropdown with dedicated drawer
- Add module tab rename: pencil icon on hover opens popover with
validation, fixed-width icon container prevents layout shift
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: remaining module-mode changes from working branch
- Backend parser updates for WAC detection
- CLI sync/types updates for raw app path and module support
- Frontend UI polish (Dev.svelte, ScriptRow, script hash page)
- Test fixture updates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(cli): add test for module modification detection in generate-metadata
Verifies that modifying a single module file re-triggers stale
detection and only the changed module is listed, not all modules.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(backend): critical fixes from PR review
- Fix hardcoded dev path in bun_executor.rs WAC v2 wrapper — use
"windmill-client" import instead of absolute filesystem path
- Fix missed no_main_func → auto_kind rename in parser TS test
- Add modules column to clone_script SQL (windmill-common and
windmill-api-workspaces) so cloned scripts retain their modules
- Add modules: None to RawCode structs in worker tests
- Restore complete sqlx cache (merge main's cache + our new queries)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(backend): fix clone warning treated as error in CI
Change `.clone()` on double reference to `*k` dereference in
scripts.rs hash implementation. Update sqlx cache with new query
hashes from modified clone_script SQL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(frontend): use published parser wasm versions for CI build
The local file:// paths for windmill-parser-wasm-py and
windmill-parser-wasm-ts don't exist in the Cloudflare Pages build
environment. Revert to published npm versions (1.655.0).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(frontend): update parser wasm packages to 1.657.2
Use newly published windmill-parser-wasm-ts and windmill-parser-wasm-py
v1.657.2 which include auto_kind/WAC detection changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(frontend): regenerate package-lock.json for npm ci compatibility
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(frontend): use main's lockfile as base, update only parser wasm packages
Regenerating package-lock.json from scratch pulled different dependency
versions causing svelte-check type errors. Instead, start from main's
lockfile and only update the two changed packages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(backend): add modules column to fetch_script_for_update query
The Script<SR> struct has a modules field (FromRow), but
fetch_script_for_update didn't SELECT modules, causing a runtime
error "no column found for name: modules" when the worker processed
dependency jobs. This was the root cause of the relock_skip test
timeout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(backend): fix script module execution for Python and Bun
- Fix modules not passed through job queue: inject _MODULES into
PushArgs.extra when pushing Code jobs so worker can extract them
- Fix Python module imports: use relative imports (from .helper)
and add sys.path.insert for module directory in wrapper
- Fix Python tests: use relative imports and empty lock to prevent
pip from resolving module names as packages
- Add local file check in Bun loader for module resolution
- Ignore Bun module test (bundle mode loader integration tracked
separately)
- Add missing modules column to fetch_script_for_update query
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(backend): remove unnecessary empty lock in Python module tests
Relative imports (from .helper) are not parsed as pip packages,
so the empty lock workaround is not needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(backend): fix module execution for Python and Bun — all tests pass
Python modules:
- Use relative imports (from .helper import greet) since scripts run
as packages
- Add sys.path.insert for module directory in wrapper to ensure local
modules take precedence over pip packages with same name
Bun modules:
- Use bundled output (./out/main.js) as wrapper import when modules
are present — the bundled output has module content inlined by
Bun.build, avoiding runtime loader resolution issues
- Add local file check in loader.bun.js onResolve to short-circuit
API URL resolution for module files on disk
Job queue:
- Inject _MODULES into PushArgs.extra when pushing Code jobs so
the worker can extract them at execution time
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: address PR review — simplify, fix correctness, remove dead code
Critical fixes:
- Replace all CLI `no_main_func` references with `auto_kind` (string)
to match the backend migration and API changes
- Remove duplicated `compute_python_module_dir` in worker.rs, use
the canonical version from python_executor.rs
High priority:
- Auto-create `__init__.py` in intermediate directories for nested
Python modules so imports like `from .utils.math import add` work
without users manually creating __init__.py files
- Remove redundant `sys_path_insert` — relative imports use Python's
package system, not sys.path
Medium:
- Fix lock file base name extraction: use regex to strip only the
final extension (`.replace(/\.[^.]+$/, '')`) instead of `indexOf(".")`
which breaks for files like `helper.test.ts`
Simplification:
- Remove dead `{#if false}` Popover block in ScriptEditor.svelte
- Guard loader.bun.js local file check to only run for relative paths
(matching the Windows loader pattern)
- Add clarifying comment on Bun dual mechanism (build + run phases)
- Add maintenance comment on manual Hash impl for NewScript
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: final review fixes — stale cleanup, baseName, auto_kind export
- Fix sync.ts baseName extraction using indexOf(".") → regex
(same fix as script.ts/metadata.ts, missed this instance)
- Add stale module file cleanup in writeModulesToDisk: removes files
from __mod/ that are no longer in the modules map before writing,
fixing the pull→push cycle that couldn't delete modules
- Log warning when _MODULES serialization fails in job push instead
of silently dropping modules
- Use strict equality (===) for auto_kind comparison
- Exclude auto_kind from workspace export — it is auto-detected by
the parser at deploy time from script content
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): remove auto_kind from push, comparison, and metadata
auto_kind is auto-detected by the parser at deploy time, so the CLI
should not send it, compare it, or write it to script.yaml.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove erroneously added backend/backend/.sqlx directory
Duplicate .sqlx cache was committed at the wrong nested path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback + fix CI dead_code warning
Frontend (ScriptEditor.svelte):
- Fix switchToMain() missing lastSyncedCode update — prevents stale
code sync on external changes while editing a module tab
- Fix formatAction saving module code to main script's localStorage
draft — now saves main code when on a module tab
- Fix non-null assertion on inferModuleLang in renameModule — fall
back to original language instead of force unwrap
- Remove redundant activeModuleTab truthy check in runTest
CLI (script.ts):
- Clean up empty directories after removing stale module files in
writeModulesToDisk
Backend:
- Add path traversal guard in write_module_files — reject module
paths containing ".."
- Fix dead_code warning on auto_kind field in workspace export struct
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(frontend): improve auto_kind UX + address review findings
- Rename "Include without main function" toggle to "Include library
scripts" in script list (ItemsList.svelte)
- Update NoMainFuncBadge: "No main" → "Library" with clearer tooltip
- Filter module file extensions by main script language — Python
scripts only allow .py modules, TypeScript only .ts, etc.
- Split flushModuleState into flushModuleContent (no UI side-effect)
and flushModuleState (flush + reset tab), reducing duplication
- Dynamic placeholder and hint text in add module popover based on
main script language
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: store hashed tokens in the token table instead of plaintext
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address review issues in token hash migration
- Update all base.sql fixtures to include token_hash/token_prefix columns
- Keep plaintext token for webhook tokens (needed for URL reconstruction)
- Restore get_token_by_prefix to query DB for webhook tokens
- Fix down migration to delete NULL-token rows before restoring NOT NULL
- Update parser fixture standalone schema
- Update EE dedicated_worker_ee.rs to use token_hash/token_prefix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore sqlx offline cache (only add new query files)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: keep writing plaintext token column for backward compat
Write to token column alongside token_hash until MIN_VERSION_SUPPORTS_TOKEN_HASH
(1.649.0) is reached. This ensures older workers can still authenticate
during rolling upgrades. Remove the separate UPDATE in new_webhook_token
since create_token_internal now writes plaintext directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: branch on MIN_VERSION to write plaintext token or null
Check MIN_VERSION_SUPPORTS_TOKEN_HASH at runtime: write plaintext to
token column while old workers exist, switch to NULL once all workers
are >= 1.649.0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: set MIN_VERSION_SUPPORTS_TOKEN_HASH to 1.650.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use token_hash for email lookup and expiry notifications
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: rotate webhook tokens instead of recovering plaintext from DB
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: use token_hash for native trigger token lookups and deletes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* sqlx
* refactor: drop webhook_token_prefix from native_trigger table
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: backward compat for token rotation and make webhook_token_hash NOT NULL
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: prevent panic on short superadmin secret token prefix
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: prevent panic on short superadmin secret token prefix
Replace all `token[0..TOKEN_PREFIX_LEN]` slicing with
`token.get(..TOKEN_PREFIX_LEN).unwrap_or(token)` to prevent
panics when a token shorter than 10 chars is provided (e.g.
malformed Authorization header, short superadmin secret).
Co-authored-by: hugocasa <hugocasa@users.noreply.github.com>
* fix: prevent panic on short token prefix slicing
Replace all `token[0..TOKEN_PREFIX_LEN]` with safe
`token.get(..TOKEN_PREFIX_LEN).unwrap_or(token)` to prevent panics
on malformed tokens shorter than 10 characters.
Co-authored-by: hugocasa <hugocasa@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Revert "fix: prevent panic on short superadmin secret token prefix"
This reverts commit 37ec2e5ad5.
* revert: remove unnecessary defensive token prefix slicing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add token_hash to end_user_email test fixture
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test: add integration tests for token hash migration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: correct token_hash test assertions for cache and version
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: add plaintext column removal reminder to test fixtures
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: log count of orphaned triggers deleted during migration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: preserve orphaned triggers with error instead of deleting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: rename token_expiry_notification.token to token_hash and copy owner/expiration in rotate
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: hash existing plaintext values before renaming token_expiry_notification column
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: remove unnecessary length check in token_expiry_notification migration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* update dates and version
* updat ee ref + sqlx
* improve mcp migration
* fix: atomic token rotation with rollback on trigger update failure
rotate_webhook_token now atomically inserts the new token and deletes
the old one in a single transaction, preventing token leaks.
Returns new_token_hash so callers can clean up the new token if their
subsequent trigger update fails (which involves external HTTP calls
and cannot be in the same DB transaction).
- Handler: wraps post-rotation work; deletes new token on failure
- Google renewal: deletes new token if service_config update fails
- Tests updated to match new atomic semantics
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* higher min version
* fix: defer old token deletion to avoid breaking triggers on update failure
rotate_webhook_token now keeps the old token alive and returns
old_token_hash. Callers delete it only after the trigger row has been
successfully updated. If the external service call or DB update fails,
the trigger keeps working with the old token.
Worst case: if the best-effort delete fails, the old token leaks as an
extra DB row — harmless compared to breaking the trigger.
Also update summarized_schema.txt for renamed columns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 2d0823a471014e2bc2d898c63518323946b7474f
This commit updates the EE repository reference after PR #437 was merged in windmill-ee-private.
Previous ee-repo-ref: 7aef8b06cb6f54c2bc89dd57b70947deed72553c
New ee-repo-ref: 2d0823a471014e2bc2d898c63518323946b7474f
Automated by sync-ee-ref workflow.
* fix: prevent panic on short tokens by using safe prefix extraction
Add safe_token_prefix() helper that uses .get(..TOKEN_PREFIX_LEN).unwrap_or(token)
instead of direct slice indexing, preventing panics when tokens are shorter than
10 characters (e.g., short superadmin secrets or malformed Bearer tokens).
Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: HugoCasa <hugo@casademont.ch>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: hugocasa <hugocasa@users.noreply.github.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>
* feat: add preprocessor support for dedicated workers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee-repo-ref.txt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract transform_and_run helper in python dedicated wrapper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add preprocessor support for bunnative scripts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: resolve unused postprocessor variable in python wrapper
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: add workflow_dispatch trigger to backend integration tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: bunnative fixture lock format and PrewarmedIsolate::spawn callers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: update generate_dedicated_worker_wrapper callers in bun_jobs test
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: use non-dedicated workers in preprocessor integration tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: prewarm preprocessor isolate for bunnative dedicated workers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: flatten bunnative dedicated worker preprocessing into single result path
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use labeled block instead of async block for EE compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update commit reference in ee-repo-ref.txt
* chore: update ee-repo-ref to e36945b987f7904fa984181baf3124e7b2722bd1
This commit updates the EE repository reference after PR #445 was merged in windmill-ee-private.
Previous ee-repo-ref: 8a2625833452aadb8907242bf502b24ca2dffd73
New ee-repo-ref: e36945b987f7904fa984181baf3124e7b2722bd1
Automated by sync-ee-ref workflow.
* Fix merge conflict in ee-repo-ref.txt
Resolve merge conflict in ee-repo-ref.txt
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Two fixes:
1. When a parallel branchall/forloop has a `stop_after_all_iters_if` expression
that fails (e.g. bad JS syntax), the error was propagated with `?`, causing
the transaction to roll back the parallel index increment. Since all parallel
jobs were already completed, nothing could ever increment the index again and
the flow hung forever. Now the error is caught and converted to a stop-early
failure so the transaction commits and the flow fails gracefully.
2. Expressions like `results.a.length` in step input transforms resolved to null
because the `handle_full_regex` fast path intercepted them and used
PostgreSQL's `#>` JSON path operator, which can't resolve JS runtime
properties like `.length` on arrays. Now the fast path skips expressions
ending with JS-only properties (like `length`), falling through to full
QuickJS evaluation where they work correctly.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: write fallback package.json for codebase mode to fix nsjail ERR_INVALID_PACKAGE_CONFIG
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test: add e2e tests for codebase mode with and without nsjail
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: auto-heal corrupted python runtime cache on remote workers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Revert "fix: auto-heal corrupted python runtime cache on remote workers"
This reverts commit 0ea013a554.
* feat: make WINDMILL_DIR configurable via environment variable
Allow users to configure the base directory for Windmill's tmp/cache files
via the WINDMILL_DIR env var (default: /tmp/windmill). This fixes Python
runtime cache corruption on RHEL systems where systemd-tmpfiles-clean
removes files from /tmp.
Converts TMP_DIR (renamed to WINDMILL_DIR) and all derived cache directory
constants from compile-time const &str (concatcp!) to runtime lazy_static
String values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee ref
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee ref
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: deref ERROR_DIR lazy_static for AsRef<Path> and Display traits
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee ref to branch name for CI compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: deref lazy_static constants in all executor files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee ref
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee ref
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee ref
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: panic if WINDMILL_DIR has trailing slash
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: also reject trailing backslash in WINDMILL_DIR for Windows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: deref GO_BIN_CACHE_DIR in test utils
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace remaining hardcoded /tmp/windmill paths and validate empty WINDMILL_DIR
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: nsjail powershell mount dst, Windows path assumptions, pwsh deref consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore Windows /tmp path translation in go and bun executors
The Windows path translation replaces /tmp with the Windows temp dir
(e.g. C:\tmp) before normalizing slashes. Without this, the default
WINDMILL_DIR=/tmp/windmill produces paths without a drive letter on
Windows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update ee-repo-ref to 6fd5a2ce908235a17975ad4dbdf0051cd89334f3
This commit updates the EE repository reference after PR #436 was merged in windmill-ee-private.
Previous ee-repo-ref: e8c03e16720833230ebd1878b4c63642ecc6c80f
New ee-repo-ref: 6fd5a2ce908235a17975ad4dbdf0051cd89334f3
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* feat(cli): add consistent get/list/new subcommands for all item types
Make the CLI consistent so every item type (script, flow, app, resource,
resource-type, variable, schedule, folder, trigger) supports get/list/new
subcommands, enabling the CLI to be used as a full API client in bash
scripts with jq piping.
- Add --json flag to all list commands for machine-readable output
- Register explicit "list" subcommand alongside default action
- Add "get <path> [--json]" subcommand to fetch single items from API
- Rename "bootstrap" to "new" for script/flow, keep "bootstrap" as alias
- Add "new" subcommand for resource, resource-type, variable, schedule,
folder, and trigger to create local template YAML files
- Update cli-commands skill documentation for wmill init
- Add integration tests for all new commands
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* feat: install wmill CLI in Docker images and use it for bash variable/resource access
- Install windmill-cli via bun in all Dockerfiles that include bun
- DockerfileCli: switch from node:slim to oven/bun:slim
- CLI: auto-configure from WM_WORKSPACE/WM_TOKEN/BASE_INTERNAL_URL env vars
as last-resort fallback when no workspace is configured
- Frontend: replace curl-based bash snippets with wmill variable/resource get
- Add backend integration tests for wmill CLI in bash scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ci): install windmill-cli in backend test workflow
Ensures wmill is available on PATH for bash integration tests
that use `wmill variable get` and `wmill resource get`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(cli): replace @std/* Deno dependencies with Node.js equivalents
Replace @std/log with a lightweight custom logger (core/log.ts),
@std/path with node:path, and @std/yaml with the yaml npm package.
Also fix process hang on exit, add --node option to install_dev.sh,
and add missing hasRequiredPermissions to NpmProvider.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* all
* all
* refactor(cli): replace @ayonli/jsext and @std/encoding with lightweight alternatives
Replace @ayonli/jsext (8.4MB) with tar-stream (32kB) for tar creation,
replace @std/encoding with Node.js Buffer.toString("hex"), and fix
@windmill-labs/shared-utils to use direct npm instead of JSR mirror.
Also resolve merge conflicts in sync.ts and fix pre-existing type errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(cli): use singleQuote YAML output and pass yamlOptions in gitsync pull
The yaml library defaults to double quotes, but the codebase (and tests)
expect single-quoted strings. Add singleQuote: true to yamlOptions and
pass yamlOptions to gitsync-settings pull writeFile calls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* all
* fix(cli): address code review feedback
- Install CLI from source in backend tests instead of npm
- Fix script bootstrap catch block to re-throw "File already exists"
- Add type-safe local variable after trigger kind validation
- Use created_by instead of policy.on_behalf_of for app get output
- Note --kind is recommended for faster trigger lookup in help text
- Document node symlink purpose in Dockerfiles
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ci): use /usr/bin for wmill wrapper to ensure it's in PATH
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ci): install wmill to ~/.local/bin to avoid permission issues
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci(backend): switch to Blacksmith runner and add cargo caching
- Switch from ubicloud-standard-16 to blacksmith-16vcpu-ubuntu-2404 for faster NVMe-backed builds
- Add stickydisk for cargo target directory (persistent NVMe cache across runs)
- Add cache for cargo registry and git dependencies
- Upgrade DuckDB FFI cache from actions/cache@v3 to useblacksmith/cache@v1
- Enable CARGO_INCREMENTAL=1 to benefit from persistent target cache
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix ci
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add .npmrc support for private npm registries
Add a new `npmrc` instance setting that accepts full .npmrc file content
for configuring private npm registries. Works with bun (native .npmrc
support since 1.1.18), deno (native .npmrc support in 2.x), and the npm
proxy (parses default registry + auth token from .npmrc).
Legacy `npm_config_registry` and `bunfig_install_scopes` fields are now
hidden when empty, so new users only see the .npmrc field. Also fixes a
pre-existing race condition where gen_bunfig was called after
start_child_process.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: improve operator ConfigMap settings handling
- Protect jwt_secret and min_keep_alive_version from deletion (add to
PROTECTED_SETTINGS)
- Expose jwt_secret in config exports (remove from HIDDEN_SETTINGS)
- Reject empty/null jwt_secret values with warning
- Clamp retention_period_secs to 30 days max on CE builds
- Improve apply_settings_diff logging: distinguish Created/Updated/Deleted
with from/to values and unchanged count summary
- Add sensitive value masking in logs with partial redaction (prefix/suffix)
for top-level secrets and nested sub-field masking for oauths, smtp,
object_store_cache_config, custom_instance_pg_databases
- Sort global_settings keys alphabetically in YAML export
- Order worker_configs with "default" and "native" first in YAML export
- Add tests for sorted YAML serializer
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review feedback
- Fix redact_string panic on multi-byte UTF-8 by using chars() instead
of byte-length slicing
- Protect jwt_secret from deletion via direct API
(set_global_setting_internal rejects empty/null with BadRequest)
- Add code comment documenting jwt_secret visibility trade-off
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: switch operator from CRD to ConfigMap
Replace the WindmillInstance CRD with a plain ConfigMap for the K8s
operator. This simplifies deployment (no CRD to install/manage, no
ClusterRole for custom API groups) while keeping the same config schema.
- Replace crd_ee.rs with configmap_ee.rs (parses data.spec YAML key)
- Rewrite reconciler_ee.rs: ConfigMap watcher + Event recorder instead
of CRD Controller + status subresource
- Add license_key preservation: if absent/empty in ConfigMap but present
in DB, the DB value is kept
- Remove print_crd_yaml() and "operator crd" subcommand
- Drop schemars, chrono, instance_config_schema dependencies
- Delete manifests/crd.yaml
- Update K8s example and README for ConfigMap approach
- RBAC now only needs a namespace-scoped Role (not ClusterRole)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add superadmin YAML export endpoint and remove cache_clear from operator config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add windmill-operator crate for Kubernetes CRD-based instance config
Introduces a new `windmill-operator` crate that enables declarative
management of Windmill instance configuration via a Kubernetes
`WindmillInstance` CRD. The operator watches CRD resources and performs
full declarative sync of global_settings and worker configs to the
database, supporting GitOps workflows for instance-level configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add tests for windmill-operator CRD and db_sync
- 9 unit tests for CRD serialization, deserialization, metadata, and
status field behavior
- 15 integration tests for db_sync using #[sqlx::test] with full
declarative sync coverage: upsert, delete, protected keys,
idempotency, worker config prefix handling, and end-to-end sync
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Replace untyped BTreeMap CRD fields with typed structs for schema validation
GlobalSettings, SmtpSettings, IndexerSettings, and WorkerGroupConfig now
have explicit typed fields with serde(flatten) catch-all for forward
compatibility. The generated CRD YAML includes a full OpenAPI v3 schema
that Kubernetes validates on kubectl apply.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Type opaque serde_json::Value CRD fields with real structs
Replace most remaining serde_json::Value fields in WindmillInstance CRD
with properly typed structs derived from the codebase:
- oauths: BTreeMap<String, OAuthClient>
- otel: OtelSettings
- otel_tracing_proxy: OtelTracingProxySettings with ScriptLang enum
- critical_error_channels: Vec<CriticalErrorChannel> (untagged enum)
- critical_alerts_on_db_oversize: DbOversizeAlert
- ducklake_settings: DucklakeSettings with nested catalog/storage types
- custom_instance_pg_databases: CustomInstancePgDatabases
- autoscaling (worker config): AutoscalingConfig with integration struct
- custom_tags, default_tags_workspaces: Vec<String>
- default_tags_per_workspace: bool
Still opaque (serde_json::Value): object_store_cache_config (kube-core
can't generate schemas for internally-tagged enums), secret_backend
(EE-private), slack, teams (no clear struct definitions).
Regenerated CRD YAML with full OpenAPI schema (352→703 lines).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Unify instance config types and add bulk GET/PUT API
Move all typed settings (GlobalSettings, WorkerGroupConfig, etc.) from
windmill-operator/crd.rs into windmill-common/instance_config.rs so both
the API server and operator share a single source of truth. Add diff/apply
logic (Merge mode for UI, Replace mode for operator) and InstanceConfig::from_db().
Add GET/PUT /settings/instance_config endpoints so the frontend loads all
settings in 1 call instead of 42, and saves with a single bulk PUT. The
backend handles the diff internally, running pre-write hooks for changed keys.
Refactor windmill-operator/db_sync.rs to use the shared diff+apply functions
and slim crd.rs down to the CRD wrapper with re-exports.
Includes 32 unit tests and 30 integration tests covering serialization,
diff logic, DB roundtrips, protected settings, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Form/YAML toggle to instance settings UI
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: show Form/YAML toggle regardless of hideTabs prop
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: replace toggle button group with simple YAML toggle
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: mask sensitive fields in YAML view with show/hide toggle
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: hide internal settings and mask sensitive fields in YAML view
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: hide jwt_secret and min_keep_alive_version from API and config exports
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* all
* feat: add secretKeyRef support for sensitive fields in operator CRD
Allow sensitive fields (license_key, hub_api_secret, scim_token,
smtp_password, OAuthClient.secret, custom PG user_pwd) to reference
Kubernetes Secrets via the standard secretKeyRef pattern instead of
inlining values as plaintext YAML. The reconciler resolves all refs
by reading K8s Secrets before syncing to the database.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* all
* all
* fix: merge main and update dev environment docs
Resolve merge conflicts from origin/main, fix duplicate
UV_INDEX_STRATEGY_SETTING import, and add Playwright MCP
testing instructions to CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* fix: init tracing for CLI subcommands and deduplicate setting side-effects
Initialize tracing subscriber before early-return CLI paths (sync-config,
operator) so tracing calls are not silently dropped. Refactor
set_global_setting_internal to call run_setting_pre_write_hook instead of
duplicating the side-effect logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add `wmill instance get-config` CLI command
Dumps the current instance config (global settings + worker configs) as
YAML. Supports --output-file to write to a file instead of stdout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace leftover common:: references in dependency_map test
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add missing deno_core/mcp features and gate dead code in permissions test
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: parse Python datetime.datetime and datetime.date type annotations correctly
The Python parser only matched ExprKind::Name for type annotations, so
`datetime.datetime` (an Attribute expression) silently fell through to
Typ::Unknown and no datetime picker was shown in the UI.
- Extend parse_expr to resolve `datetime.*` attribute access (alongside
the existing `wmill.*` handling)
- Add Typ::Date variant for `datetime.date` → JSON schema format "date"
- Update python worker to import and convert `date.fromisoformat()`
- Update argSigToJsonSchemaType, AI types, schema validation, and SQL
datatype wasm for the new Date variant
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* all
* all
* all
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add 7 #[ignore] e2e tests (one per trigger type) that fire real messages
to external services and verify job creation in v2_job. Also add 9 DB-level
CRUD tests for MQTT, GCP, and Email triggers.
Includes helper shell scripts in tests/fixtures/ to start/stop each
external service (MQTT, WebSocket, Postgres replication, Kafka, NATS,
SQS via LocalStack, GCP Pub/Sub emulator).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The handler expected Path((w_id, name)) but the route was registered
as /is_owner without :name, making the endpoint unreachable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: limit test threads to 16 to prevent postgres pool exhaustion
Running all tests with unlimited parallelism exhausts postgres
max_connections (default 100), causing sqlx::test databases to fail
setup and producing spurious RowNotFound errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: CI ruby env vars and mysql test binary coercion
- Ruby executor reads RUBY_BUNDLE_PATH and RUBY_GEM_PATH but CI was
setting BUNDLE_PATH and GEM_PATH, causing "Executable bundle not
found on worker" errors.
- MySQL test CAST(CONCAT(...) AS CHAR) returns binary type when param
is bound as bytes. Use CONVERT(? USING utf8mb4) to ensure character
result type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The test file used old JobPayload/FlowValue field names that were
refactored into DebouncingSettings/ConcurrencySettings structs.
Remove the test file, fixture, feature flag, and cfg gate in monitor.rs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MySQL CONCAT with binary params returns VARBINARY, causing base64
encoding. Use CAST(... AS CHAR) to force character type output.
Ruby executor doesn't support keyword parameters (name:), use
positional parameters instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: isolate deno_core into windmill-runtime-nativets subcrate
Remove deno_core from flow eval and isolate nativets V8 runtime into a
dedicated subcrate so deno_core compilation no longer blocks
windmill-worker or windmill-api.
- Create windmill-jseval crate: QuickJS-based JS eval for flow
expressions and batch rerun, extracted from windmill-worker
- Create windmill-runtime-nativets crate: all deno_core/V8 deps and
nativets script execution, with build.rs snapshot generation
- Simplify windmill-worker: remove all deno_* direct deps, empty
build.rs, gate nativets behind optional dep
- Update windmill-api: use windmill-jseval for batch rerun instead of
deno_core, remove deno_core feature entirely
- Add nativets integration tests (nativets_jobs.rs) and parallel
stress test (nativets_stress.rs, 8 workers x 200 jobs)
- Remove dead code: deno flow eval path, USE_QUICKJS env var,
parity tests (replaced with 63 standalone expected-value tests)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review feedback for deno_core isolation
- Deduplicate unsafe_raw() into windmill-common/src/utils.rs (single source)
- Delete orphaned runtime.js and windmill-client.js from windmill-worker/src/
- Fix operator precedence in windmill-jseval with explicit parentheses
- Remove unnecessary return keyword in heap limit callback
- Remove redundant as usize casts
- Remove ~150 lines of commented-out code from runtime.js
- Remove commented-out #[cfg] in build.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* otel ee
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* test: add integration tests for all feasible language runtimes in CI
Add integration tests and CI setup for languages that were previously
untested. Each test runs a simple "hello world" job through the full
worker pipeline to verify end-to-end execution.
New language tests added to worker.rs:
- Nativets (4 tests): basic string, numeric args, object return, datetime
- Bunnative: TypeScript execution via Bun native runtime
- CSharp: .NET compilation and execution (feature-gated)
- PHP: PHP script execution (feature-gated)
- Ruby: Ruby script execution (feature-gated)
- MySQL: SQL query via async MySQL client (feature-gated)
- PowerShell: pwsh script execution
- PostgreSQL: SQL query against test database
CI changes (backend-test.yml):
- Add MySQL 8.0 service container
- Add setup-php (8.3 + composer), setup-ruby (3.3), pwsh install
- Enable feature flags: csharp, php, ruby, mysql
- Pass language binary paths: PHP_PATH, COMPOSER_PATH, RUBY_PATH,
BUNDLE_PATH, GEM_PATH, POWERSHELL_PATH, DOTNET_PATH
- Uncomment and modernize CSharp test (was commented out)
- Increase test timeout 16m -> 20m for additional runtimes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* sqlx
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract windmill-dep-map crate for parallel api/worker compilation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve WebhookShared type mismatch and missing enterprise propagation
- Make windmill-api webhook_util re-export from windmill-common instead of
duplicating types, fixing Extension<WebhookShared> mismatch between
windmill-store and windmill-api
- Add windmill-api-jobs/enterprise to windmill-trigger enterprise feature
so check_license_key_valid is available when trigger subcrates enable
enterprise on windmill-trigger
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: stop trigger features from unconditionally enabling enterprise
Move enterprise propagation for all trigger subcrates from individual
trigger feature definitions to the enterprise feature itself, so
enterprise is only enabled when explicitly requested.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: remove unused pub use re-exports and disable CI cargo cache
- Remove unused re-exports from windmill-worker/src/lib.rs:
trigger_dependents_to_recompute_dependencies, handle_job_error,
and unused bun/otel items
- Fix callers to use direct module paths instead
- Add windmill-dep-map as dev-dependency for tests
- Disable cargo cache in backend-check CI (faster from-scratch builds)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore bun re-exports used by tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* chore: re-enable cargo cache for check_ee_full CI job
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: reuse outer tx for schedule push in commit_completed_job
Instead of calling handle_maybe_scheduled_job(db) which opens its own
connections (peak=3), inline the schedule push using a savepoint on the
outer transaction. Auth is fetched via the tx connection using
fetch_authed_from_permissioned_as_conn, and push_scheduled_job runs
on a savepoint so failures roll back only the push, not the completion.
On push failure: savepoint rolls back, schedule is disabled on the outer
tx, and the zombie return path is preserved if disabling also fails.
Peak connections drop from 3 to 1 (or 2 on cold RunnableSettings cache).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* all
* fix: extract shared try_schedule_next_job to unify schedule push paths
Replace the two diverging schedule-push implementations (inlined in
commit_completed_job and standalone handle_maybe_scheduled_job) with a
single try_schedule_next_job that reuses the caller's transaction via
savepoints. This eliminates extra pool connection usage in the
worker_flow.rs path and ensures consistent retry/error semantics.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add failpoint markers to try_schedule_next_job
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove plan.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove inner retry loop from try_schedule_next_job, add caller-level retries
The 10-retry x 5s-sleep loop inside try_schedule_next_job held locks on
v2_job_completed/v2_job_queue for up to ~45s when running inside the
outer commit_completed_job transaction.
Now try_schedule_next_job makes a single attempt and returns errors to
the caller. Non-retryable errors (QuotaExceeded, NotFound) disable the
schedule immediately inside the function. Transient errors are returned
for the caller to retry:
- commit_completed_job path: outer backon retry (10x3s) retries the
entire transaction including the schedule push, so no locks are held
during sleep.
- handle_flow path: new backon retry (10x3s) wraps begin/push/commit
with a fresh transaction per attempt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clear push_err after successful schedule disable to prevent stuck schedules
When try_schedule_next_job disables the schedule for non-retryable errors
(NotFound, QuotaExceeded), clear the error so the caller commits the tx
(persisting the disable). Previously, the error propagated up, causing the
tx to be dropped and rolling back the disable — leaving the schedule
permanently enabled but broken.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add 5s timeout on push_scheduled_job, clean up handle_flow error handling
- Add tokio::time::timeout(5s) around push_scheduled_job inside
try_schedule_next_job to bound worst-case lock holding per attempt
- Remove unreachable QuotaExceeded/NotFound match arms in handle_flow
(these errors are handled internally by try_schedule_next_job)
- Add report_error_to_workspace_handler_or_critical_side_channel in
handle_flow when post-exhaustion schedule disable fails
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: return SchedulePushZombieError when both schedule push and disable fail
When handle_flow cannot push the next scheduled job AND cannot disable the
schedule, return a SchedulePushZombieError so the worker leaves the flow job
in the queue for zombie detection to restart. This prevents stuck schedules
where neither the next tick was pushed nor the schedule was disabled.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>