* fix: enforce auth guards on app component preview execution
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: guard previewed runnable path and worker tag in app preview
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: validate app_script id ownership and keep root push isolation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: scope app preview guards to operator check + referenced runnables
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: require jobs:run scope and tag check on app preview (apps:run escalation)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add wmill protection-rules pull/push CLI commands
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: use directional keys for protection-rules pull --json diff
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — exit non-zero on failure, resolve override workspace key
- failure paths in pull/push now exit 1 so CI/scripts detect failed reconciles
- --override writes under the resolved workspace key (findWorkspaceByGitBranch),
not the raw branch, so gitBranch-mapped entries aren't left inert
- pull --replace clears a shadowing protectionRules override so top-level takes
effect (was an infinite pull --diff loop)
- push reports applied create/update/delete counts on partial failure and warns
loudly when an empty list would wipe all backend rules
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — dry-run pull --diff no longer writes; --promotion coherent
- pull --diff returns before the no-wmill.yaml bootstrap, so a dry run never
creates/mutates wmill.yaml
- pull --promotion now writes/clears the promotion target's promotionOverrides
(the same block getEffectiveSettings reads), instead of the current branch's
regular overrides — read and write are now coherent
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: move protection rules to a per-workspace protection-rules.yaml
Replaces the wmill.yaml/SyncOptions integration (top-level + overrides +
promotionOverrides) with a dedicated protection-rules.yaml keyed by workspace
name. This removes the getEffectiveSettings layering that caused the override
shadowing / promotion-coherence / dry-run bugs entirely.
- protection-rules.yaml: { <workspace>: ProtectionRuleEntry[] }, keys must
match wmill.yaml 'workspaces' (source of truth for backend id/baseUrl/token)
- commands reduced to: pull/push [workspace] | --all, with --dry-run
- per-workspace auth resolved via tryResolveBranchWorkspace + setClient
- push remains a full reconcile (create/update/delete) with delete confirm,
empty-list wipe warning, partial-failure reporting, non-zero exit on failure
- conf.ts reverted to main; SyncOptions no longer carries protectionRules
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — honor explicit --base-url/--token in protection-rules
configureClientForWorkspace bypassed the credential precedence other commands
use: explicit --base-url/--token now work for stateless CI (no stored profile
or wmill.yaml baseUrl needed), and an explicit --token overrides a stored
profile's token. The backend workspace id still derives from the wmill.yaml
mapping (feature invariant).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address cubic review — consistent status on partial --all failure
cubic found that pull/push reported success:true while exiting non-zero on
partial --all failures, and that the push command description was missing from
the generated CLI docs.
- pull/push now report success:false + partialFailure:true (and exit 1) when
any --all workspace fails; success:true only on full success
- .description() calls use single string literals (not + concatenation) so
system_prompts/generate.py parses them; regenerated CLI docs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — --json-output must emit only JSON on stdout
Codex flagged that workspace resolution (tryResolveBranchWorkspace's log.info)
and push's empty-list delete warning print to stdout before the JSON payload,
breaking machine callers. Silence human logs via log.setSilent(true) as the
first action when --json-output is set (before readConfigFile / resolution);
log.error still goes to stderr.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [ee] feat(indexer): observability for unavailable search index
A user hit `Not found: There is no index reader to search from` when
searching service logs and could not tell whether it was a config
error or a bug, and asked for visibility into the indexer status
(WIN-1956).
Backend (EE companion PR):
- Replace the opaque error with an actionable message explaining the
likely causes (indexer disabled, still starting, or blocked
acquiring the indexer lock) and pointing to the status panel.
- Add a coarse `state` (running | stale | never_started) to
`/indexer/status`, derived from the lock row, distinguishing a
never-configured indexer from a stale/blocked one.
Frontend:
- Instance Settings > Indexer now shows Running / Stale / Not started
with a tooltip explaining what to check for each.
- Service logs search now catches failures and shows an inline,
actionable Alert instead of an unhandled rejection.
Fixes WIN-1956
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 017d36418a65ce5c840c502e3174df0c393612ba
This commit updates the EE repository reference after PR #580 was merged in windmill-ee-private.
Previous ee-repo-ref: 18b7e1b30a1ff582c4a072580bbb8aec34e22cdc
New ee-repo-ref: 017d36418a65ce5c840c502e3174df0c393612ba
Automated by sync-ee-ref workflow.
* fix(indexer): address review nits
- IndexerMemorySettings: older backends without `state` reporting
`is_alive: false` now show "Stopped" (red) again instead of
falling through to "Unknown" (codex/cubic P2).
- ServiceLogsInner: clear stale logs/counts on a failed search so the
error isn't shown alongside results from a previous query (codex P2).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix(frontend): open customer portal in popup synchronously to bypass Safari blocker
Safari blocks window.open() called after an await because it loses the
user-gesture context. Open a blank tab synchronously on click, then
assign location.href once the portal URL resolves.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(backend): wire dev_override feature flag in backend crate
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: export audit logs to dedicated object store folder
* fix: gap-free audit export via snapshot-xmin gate and stable object keys
* test: add integration test for audit log object store exporter
* fix: cursor audit export on snapshot xmin to prevent id-leapfrog loss
* fix: protect audit s3 checkpoint from config sync and bound export interval
* fix: anchor audit s3 checkpoint at enable time to not skip first-window rows
* fix: anchor first audit export at the enable transaction's xid
* fix: use epoch timestamp floor on first audit export run to not drop old backlog
* fix: anchor audit export at startup for env-var enable path
* fix: anchor audit export via enabling-txn snapshot xmin trigger
* fix: bound the bootstrap audit export to MAX_XID_INTERVAL per tick
* refactor: store audit export cursor in background_task_state, add status endpoint
* docs: align store_audit_logs_s3 setting text with the actual enable-boundary contract
* [ee] refactor: move audit s3 export core logic to EE, gate on Enterprise license
* chore: update ee-repo-ref to ec3cd353245e1cdf6a290528dbd7f2ac2498386c
This commit updates the EE repository reference after PR #579 was merged in windmill-ee-private.
Previous ee-repo-ref: 4ffc6d5f874e64d7dc4a147b4e73baa6c44867a5
New ee-repo-ref: ec3cd353245e1cdf6a290528dbd7f2ac2498386c
Automated by sync-ee-ref workflow.
---------
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix(autoscaling): full-scale from below min_workers when backlog exceeds threshold
Bump EE ref to pull in the autoscaling fix: when active worker count is
below min_workers and a relevant tag's queue depth already exceeds
full_scale_jobs_waiting, scale straight to max_workers instead of slowly
ramping to min_workers first.
Companion EE PR: windmill-labs/windmill-ee-private#improve-pr-9209
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to b4d68e40430cf0300b5d37734d1505fd743f1059
This commit updates the EE repository reference after PR #578 was merged in windmill-ee-private.
Previous ee-repo-ref: 99810eb763703ef0f4b3311338e0e65f53544158
New ee-repo-ref: b4d68e40430cf0300b5d37734d1505fd743f1059
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix: enable jemalloc background purge to prevent worker RSS growth
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: drop decay overrides, keep only jemalloc background_thread
The background thread is the actual fix; jemalloc's default decay
windows (dirty 10s, muzzy 0) are correct for months-long workers and
muzzy_decay_ms:5000 was more retentive than the default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: scope SimpleEditor webview paste to focused editor instance
* fix: scope webview clipboard paste to focused editor instance
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: bail on missing selection instead of pasting at document start
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: hide SimpleEditor paste sink input from a11y tree and tab order
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: advance postgres replication slot lsn via periodic standby status updates
* test: add e2e regression test for postgres replication slot lsn advancement
Drives sustained change traffic so the slot freeze reproduces deterministically (fails pre-fix at the 20s deadline, passes post-fix within ~10s). Also wires the postgres_trigger feature through windmill-test-utils and the integration-tests crate so the postgres trigger e2e tests are actually runnable.
* fix: honor SAML RelayState to redirect to deep link after SSO login
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: bump ee-repo-ref for SAML RelayState validator test
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to a3fefe85f5f2f52bb473fa47acc9efa8fd0b2206
This commit updates the EE repository reference after PR #577 was merged in windmill-ee-private.
Previous ee-repo-ref: 445a22536b1a6c342cde0baa6fbca9e25092f94b
New ee-repo-ref: a3fefe85f5f2f52bb473fa47acc9efa8fd0b2206
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix: reject path traversal in MCP endpoint path parameters
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: narrow MCP path-param validator to structural escapes only
Codex review: rejecting whitespace/`:`/`@` regressed legitimate
Windmill paths (app paths with spaces, email-style usernames like
u/admin@windmill.dev/...). These are ordinary path-segment data in an
absolute URL and cannot redirect the request. Reject only structural
escapes: control chars, `\`, `%`, `?`, `#`, and `.`/`..`/empty segments.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the Docusign Authorization Code OAuth entry. Used by the
Docusign integration in the windmill-integrations hub (PR #128).
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat: show job status in favicon on the run page
* test: cover getJobStatusKind favicon status mapping
* chore: remove favicon unit tests
Co-authored-by: Diego Imbert <diegoimbert@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Diego Imbert <diegoimbert@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix: resolve absolute-path imports in monaco ts editor
* fix: dispose absolute-path extra libs on editor teardown and reset
* fix: skip late ata local-file callbacks after editor teardown
* fix: enforce jobs:run scope on job preview and inline endpoints
Preview/inline endpoints (run/preview, run/preview_bundle, run/preview_flow,
run/dynamic_select inline) execute arbitrary request-supplied code but only
checked folder/namespace read access, which is a no-op when path is null. A
token scoped to a specific script/flow could escape its scope and run any
code. Add a jobs:run scope check, matching other arbitrary-execution
endpoints. Advisory GHSA-vxc5-w28p-m9xw.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: scope-check dynamic_select flow branch and inline preview
Address CI review: the dynamic_select Deployed{Flow} branch ran a deployed
flow's dynamic-select code without any scope check (only the Script branch
delegated to a scope-checked handler), and run_inline_preview_script executed
request-supplied code with no in-handler scope check. Add jobs:run:flows:{path}
to the flow branch and jobs:run to inline preview; correct the misleading
comment. Expand regression tests (preview_flow case, assert success for the
broad-token case). Advisory GHSA-vxc5-w28p-m9xw.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: remove preview scope enforcement test after local validation
The regression test passed locally (3/3) and validated the fix end-to-end;
removed from the PR per maintainer preference. Advisory GHSA-vxc5-w28p-m9xw.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The dev profile's split-debuginfo = "unpacked" is coerced to "packed" on
windows-msvc, so each test-binary link spawns the shared mspdbsrv.exe PDB
type server. With 12 parallel link jobs this races the type-server cap
(LNK1318 "LIMIT (12)") and exhausts the runner disk (LNK1180), recurringly
failing the Windows release CI. CI needs no debug info, so disable PDB
generation for the dev/test profiles in this job only.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: constrain unauthenticated get_public_resource to app_theme resources
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: remove get_public_resource regression test
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: bind /etc resolver files read-only in nsjail sandboxes
* docs(nsjail): explain why per-file /etc resolver binds are load-bearing
The explicit /etc/hosts, /etc/resolv.conf and /etc/hostname binds look
like removable duplication of the read-only /etc bind above them. They
are not: on Kubernetes those files are separate kubelet bind-mounts on
top of /etc and nsjail's read-only remount is non-recursive, so without
these shadow binds they stay writable and a job can persist cross-tenant
DNS poisoning for the pod lifetime. Comment guards against a future
"dedup cleanup" silently reintroducing the vulnerability.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(nsjail): shorten the load-bearing-bind comment to 3 lines
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix: sidebar menu rendering expanded-but-empty near 768px width
The desktop sidebar branch is gated by JS (`innerWidth < 768`), but its
width was set only via Tailwind `md:` classes (`@media (min-width:768px)`).
`window.innerWidth` rounds fractional viewport widths, so at e.g. 767.8px
JS rounds to 768 and renders the desktop sidebar, while the CSS media
query does not match and no width class applies — leaving the sidebar
shell expanded with no width/content. Drop the now-redundant `md:`
prefix so width tracks the JS branch decision.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: align content offset breakpoint with sidebar JS gate
The sidebar width now follows the JS innerWidth gate, but the main
content left-offset in AiChatLayout still used the `md:` CSS media
query, leaving the two breakpoints out of sync in the same sub-pixel
band. Pass an `isMobile` flag from the layout (mirroring the sidebar's
`innerWidth < 768` condition) and gate the content padding on it with
unprefixed classes so sidebar width and content offset always flip
together.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: reset parent_hash in auto_parent when all versions at path are archived
* test: regression test for auto_parent with all versions archived
---------
Co-authored-by: windmill-internal-app[bot] <1429786+windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* fix: don't show ALLOW_PRIVATE_AI_BASE_URLS hint for malformed AI base URLs
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix: impl std::error::Error for SsrfValidationError for anyhow callers
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix: atomic bundle cache writes to prevent parallel cold-load race
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: trust-but-replace in atomic_publish_dir to never trust a stale partial cache dir
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: simplify atomic_publish_dir and add content-addressed rename-failure fallback
Revert the destroy-then-recreate dir swap (introduced concurrent-publisher
edge cases: spurious Err under a real herd, EACCES masking a stale partial)
back to a single atomic rename. Add the content-addressed exists-fallback to
atomic_write_file_bytes/atomic_copy_file so the loser of a publish race (and
Windows, where rename cannot replace an open/existing destination) treats the
already-published identical cache as success instead of failing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
windmill-parser-ts-asset only recognized writeS3File/loadS3File when
the first arg was a bare 's3://...' string literal. The actual SDK
signature takes an S3Object ({ s3, storage? }) or 's3://bucket/key'
string, which every real script uses, so object-form writes/reads were
never detected as assets. Resolve the S3Object arg the same way the
runtime parseS3Object does, mapping { s3, storage } to s3://<storage>/
<key> and feeding it through parse_asset_syntax so the path matches the
// on s3:///… trigger form. Adds regression tests.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>