* feat: wire paged object storage listing module
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: document list_stored_files_paged endpoint in openapi
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: lazily expand s3 explorer folders one level at a time
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: pin ee-repo-ref to the paged listing branch
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: share object_store credential resolution and surface listing errors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sqq2LhmWaGwP11Cf3UqWxe
* Chevron is cool
* page size 5000
* feat: make the load more row full-width, secondary and chevron-led
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sqq2LhmWaGwP11Cf3UqWxe
* fix: render newly loaded flat pages inside already-expanded folders
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: address review findings in the lazy s3 explorer
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: address review nits in the lazy s3 explorer
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref after merging main
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: document ambient credential contract and constrain max_keys schema
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: treat an exhausted page token as exhausted, not as a continuation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for canonical prefix validation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for prefix scoping and opaque cursors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: invalidate a folder's in-flight load when deleting from it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: discard a stale folder page after its level is invalidated
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for bounded local listing
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: label folders whose final path segment is empty
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: search files by any part of their path, not just folder prefix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: search files by path prefix instead of a full-bucket scan
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: guard stale search responses and describe prefix search accurately
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for the search prefix fallback fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: regenerate the served openapi specs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for the search cursor fallback fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for the bounded search scan
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: surface a failed flat listing instead of spinning forever
The flat branch of loadFiles was awaited without a catch, and loadFlatFiles
clears its loading flags only on the success tail. Every caller reaches it
un-awaited, so a rejected listing left the drawer on "Loading content" with
nothing reported. Routing the filter box through this arm made it reachable
per keystroke rather than once per open.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: give back the flat cursor when a page fails to load
"Load more" advanced `page` before requesting it, so a failed page left the
cursor pointing at a `listMarkers` slot that was never filled. The retry sent
no marker at all and silently replayed the first page, and the
`listMarkers.length == page` guard kept it there until the listing was reset.
Only reachable now that a failed page is retryable rather than a permanent
spinner.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: scope the flat cursor rollback to its own listing
The rollback matched on the page number alone, so a page that failed after a
filter or storage change could roll back the *replacement* listing once it had
reached the same number, stranding its cursor. Tie it to the generation the
request was issued under.
The delete replay loop had the mirrored problem: it re-drove `page` by hand and
carried on past a failed page, leaving `page` ahead of `listMarkers` for good.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: skip the delete replay when the fresh listing itself failed
clearAndLoadFiles dropped the result it already computes, so a failed
post-delete listing still ran the replay loop: each page advanced `page` with
an empty `listMarkers`, which never recovers because the marker-length guard
only pushes when the two agree. Every later "Load more" then replayed page one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: stop a superseded lazy load from writing into the search that replaced it
loadFolderPage resolves rather than throwing once its generation is stale, so a
filter change that switches the picker to the flat listing mid-flight left the
lazy branch free to expand a preselected file into the search's results and to
clear the search's loading flags. Guard both on the generation it started under,
as the flat branch already does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: check the listing generation throughout the reveal walk
Revealing a preselected key is a chain of round trips, so checking once at entry
left the rest of the walk free to keep loading after a filter change had already
switched the picker to the search — under the replacement generation, so the
per-level guards inside loadFolderPage saw nothing wrong.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: let a late metadata failure clear only its own preview
The handler blanked fileMetadata and filePreview without checking that its
request still owned the pane, so selecting a second file while the first was
still loading meant the first's rejection wiped the second's preview.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: key preview ownership on the request, not the selected key
Comparing the selected key let an older request speak for a newer one when both
targeted the same key, which a storage switch does, and made a request whose
selection had moved to something with no metadata return early with the spinner
still up — the case the handler exists to prevent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: clear the preview when the previewed file is deleted
The lazy branch refetches only the affected level and returns, so it never
reached the reset that the flat refresh gets from clearAndLoadFiles. The pane
renders from fileMetadata rather than from the selection, leaving the deleted
file previewed with working download, move and delete actions.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: retire the in-flight preview load when its file is deleted
Clearing the pane was not enough: a metadata response computed before the DELETE
landed still repopulated it, restoring the deleted file's preview and its
download, move and delete actions. Deleting now retires the owning request, and
the success and preview writes honour that the same way the failure path does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: clear the preview loading flag when the delete retires its request
Retiring the in-flight metadata load left nobody to report its outcome, so in
lazy mode the pane sat on "Loading..." instead of falling back to the empty
state. The delete owns the flag once it has retired the request.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: drop the regenerated openapi deref artifacts
They are generated files that CI only syntax-validates, never checks against
openapi.yaml, and the committed copies already differ from the spec they derive
from by ~9.7k lines. Regenerating here imported that pre-existing drift into a
feature diff, burying ~800 lines of actual change under ~17k lines of other
changes' staleness. Regenerating them is its own chore.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: state the flat cursor invariant once, where the cursor lives
It was spelled out at four sites, which is what AGENTS.md asks not to do. The
rule now sits on the declaration it constrains and the guards reference it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* nit ui
* fix: add the paged listing to the served openapi json
openapi_json() embeds openapi-deref.json via include_str!, and the Docker build
regenerates only the yaml artifact, so the json is served exactly as committed —
leaving the new operation out of the Scalar API reference.
Spliced in the operation and the two schemas it references rather than
regenerating, which would have re-imported ~7k lines of pre-existing drift
between the committed artifact and the spec it derives from.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: bump ee-repo-ref for the filesystem symlink boundary
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 0373b4bfdaf8dd51533552e2e4de63ceb3c18b4d
This commit updates the EE repository reference after PR #697 was merged in windmill-ee-private.
Previous ee-repo-ref: eb1a765bb9b29e0c94a6e4942c304934fa15406e
New ee-repo-ref: 0373b4bfdaf8dd51533552e2e4de63ceb3c18b4d
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 5 (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>
* fix: handle a non-member superadmin on the dev workspace settings tab
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: only seed the protections panel from a load this call produced
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: refetch rather than seed while a protection-rules fetch is in flight
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: always supersede the in-flight rules fetch instead of seeding by hand
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: refresh the dev-workspace pairing after attach and detach
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: report enforced protections, not only unconditional ones, on the paired view
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: base a new fork on the dev workspace when forking from one
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: carry dev-workspace fields on the superadmin-synthesized entry
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(fork): merge a fork deletion on evidence, not on the counters
`workspace_diff.ahead`/`.behind` record that a write happened on a side,
not what it was or who made it. That leaves one row shape undecidable: an
item the parent has and the fork does not can mean the parent added it,
the fork deleted it, or a git-sync pull reverted a deploy that had just
brought it in. #10467 kept every such row out of the merge direction,
which killed the phantom but also dropped the only way to propagate a
fork-side deletion and left a rename's old path behind in the parent.
Record the evidence instead:
- `workspace_diff` gains, per side, the last event's kind (`write` /
`delete` / `rename_from`) and origin (`authored` / `sync`). Rows
written before the migration have neither and keep #10467's behavior.
- The kind is probed from whether the path still holds an item once the
write has committed; an item kind the probe doesn't map records no
evidence rather than a deletion. Create and update are not split —
nothing at that point tells them apart for every kind, and the
comparison already recomputes existence per side.
- The origin comes from an `X-Windmill-Deploy-Origin` header the API
scopes into a task-local for the request. It is the load-bearing half:
recording `delete` alone would read a git-sync revert as a fork
deletion and reproduce the original bug. Two clients set it — `wmill
sync push` (which the git-sync auto-pull runs inside a job) and the
compare page's parent→fork "Update fork". Merging the other way stays
authored so a deletion keeps propagating up a fork chain.
- The merge direction admits a parent-only row only when the fork's last
event was an authored delete or rename-away. Such a row stays opt-in,
never bulk-selected, and reads "Removes in <parent>"; the update
direction keeps offering it back as "New".
A fork deletion and a rename now merge into the parent, a rename leaves
no duplicate behind, and a fork the parent also edited surfaces in both
directions instead of the parent silently winning.
Fixes WIN-2289
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(fork): address review — detached tallies, enum wire values, doc duplication
Codex P1: a dependency job tallies its deploy whenever it happens to finish,
and the event kind is probed from the state at that moment. If anything
removed the path in between (a git-sync revert), the stale tally read that
deletion as its own and filed it as authored — handing the merge exactly the
removal this is meant to withhold. `tally_deployed_object_changes` now takes
`Option<DeployOrigin>`; `None` bumps the counter and leaves the evidence
columns as the last vouching tally left them, and the worker path passes it.
Covered by extending the removal-origin test: a detached tally after the sync
archive must not disturb `(delete, sync)`.
Also from review:
- `fork_removed_it` compares through `DeployOrigin::as_str()` /
`DeployEventKind::as_str()` rather than repeating their wire values, so a
renamed variant can't silently make the predicate always false.
- `deploy_origin`'s module doc no longer claims `sync` is inert: it cannot
make the merge propose a removal, but it does drop a row out of both sides
of the `all_ahead_items_visible` comparison.
- `WorkspaceDiffRow` says why only the fork half of the evidence is consumed.
- The delete-vs-revert rationale is stated once (the migration) instead of
restated in eight files.
- `PATH_KEYED_TABLES` is swept by a test: its query is built at runtime, so a
wrong table name is not a compile error and would only surface as a failed
tally for that trigger kind in a fork.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(fork): let only a request task vouch for a deploy event
Round 2 found the first fix incomplete. Detaching only the failed/cancelled
dependency path left the common route untouched: a dependency job that
succeeds calls `handle_deployment_metadata` from the worker, where
`deploy_origin::current()` read as `Authored`. A sync archiving the script
while its lock generation was pending then had its deletion probed on
completion and refiled as authored — the same fabricated removal, on the
path most deploys actually take.
`current()` now returns `Option`, `Some` only inside the request scope the
API always enters. Having no scope means "not the task that served this
write", which is true of every worker-side call and needs no marking at the
call site. The integration test drives the real `handle_deployment_metadata`
off a request task instead of the tally directly, and fails without this.
Two more from the same round:
- The script dependency handler passed no `renamed_from`, unlike the flow
and app handlers next to it. A lock-generating create has no earlier
tally, so that was the only chance for the path a rename vacated to be
recorded at all — renames of Python/TS scripts left the old path in the
parent, which the bash-only manual check missed.
- The tally now drops a `renamed_from` equal to the path itself. Callers
pass the previous path whether or not the deploy moved the item, so an
unfiltered one both counted the path twice and stamped it `rename_from`
when nothing was renamed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(fork): carry a deploy's origin into the dependency job it queues
Round 3 caught the previous fix cutting too deep. Refusing a detached tally
any claim also refused its rename evidence, and a lock-generating deploy has
no other tally — so the `renamed_from` added alongside it was inert, and a
renamed flow, app or Python script still left its old path in the parent
with nothing to merge. Flows and apps always generate, so renames worked
essentially nowhere.
The two capabilities are now separate. `TallyEvidence` says whether the
tallying task served the write (`Served`, may probe what the path holds now)
or is reporting one that committed earlier (`Deferred`, may not), and each
column is written only from a source that answers for it. The origin itself
is a fact of the deploy either way, so the request stamps it into the
dependency job's args and the worker re-enters the scope with it — the last
place that knows it handing it to the only tally that will run.
Also from round 3: `WorkspaceDiffRow`'s event fields skip serializing `None`
rather than emitting `null`, matching what the schema declares (OpenAPI
3.0.3 ignores a `description` sibling of `$ref`, so those moved onto the
shared schemas).
Verified against a live worker: renaming a flow in a fork records
`(rename_from, authored)` on the vacated path and the merge offers its
removal, while the deployed path claims nothing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(fork): mark the CLI's parent-to-fork merge as sync
`wmill workspace merge --direction to-fork` is the CLI's "Update fork" and
deletes items in the fork, but without the marker the compare page sets. Its
deletions were recorded as authored fork decisions, so once the parent
recreated such a path the merge would offer deleting it there.
Also from review: an unrecognized deploy-origin arg now reads as no evidence
rather than as authored — strict where a request header is lenient, since an
unmarked request really is authored but an unreadable stored value is skew.
Reading the arg moved next to `stamp_origin_arg`, the half that writes it, so
the round trip a lock-generating deploy depends on is covered by one test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop the imports the shared arg reader made unused
CI compiles with `-D warnings`, so this was four red Backend jobs rather
than a lint.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(fork): stop a stale deferred rename from restating a removed path
Nothing orders these events. A tally that served the write made its claim
inside its own commit, but a deferred one reports a write that landed at an
unknown remove. So a lock-generating rename whose dependency job finished
after a sync had removed the vacated path could overwrite `(delete, sync)`
with `(rename_from, authored)` — the path is gone either way, so the merge
would then offer removing it from the parent on the strength of the older
event.
A deferred claim now only writes where the side has none, which is the case
it exists for: a vacated path that nothing else has spoken for. The
regression asserts the ordering directly, and fails without the guard.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(fork): record a rename's vacated path from the request that made it
The deferred mechanism could not be made correct, as round 7 showed: its
guard protected an existing row, but that row is deleted as soon as the two
workspaces agree on the path — so a rename job finishing after the
reconciliation inserted fresh, and the stale claim reappeared against
whatever the parent later recreated there. Ordering cannot be recovered
outside the row, because the row is disposable.
So the vacated path is now recorded by the request, which is inside its own
commit and whose row shares the counter's lifetime. A deploy that hands its
metadata to a dependency job — every flow and app, and any script needing a
lock — calls `tally_rename_vacated_path` once its transaction has committed;
scripts reach it through the post-commit hook they already had, which grew a
second variant rather than new plumbing.
That lets the whole deferred apparatus go: `TallyEvidence`, the origin job
arg and its round trip. `deploy_origin::current` is `Some` only inside a
request scope again, and `handle_deployment_metadata` hands `renamed_from`
to the tally only when it can answer for it — git-sync still gets it either
way, so the rename keeps naming itself in the commit message.
The vacated path's kind now reads `delete` rather than `rename_from` for
these deploys, since it is probed rather than declared. The merge treats the
two alike; only the row's tooltip is less specific.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(fork): cover raw-app renames, and stop firing CI before the lock exists
Two things the vacated-path call broke or missed:
- `create_script` reads its third return value as "no lock generation
needed" to decide whether the script is runnable now, and the new
`VacatedPath` variant made that true for renames that do generate. Those
fired dependent CI tests from the API against a version with no lockfile,
and again from the dependency job. The variant now decides it explicitly.
- Raw apps rename through `update_app_raw`, a separate route into
`update_app_internal`, which the new call had not been attached to. Both
routes now go through one helper.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(fork): assert the kind only an inline rename can record
`rename_from` is what a deploy says when it knows it moved the item, which
only the path that reports both halves from its own request can. Nothing
pinned it, and that is the side the vacated-path change touched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to a45bec03922d305aad5893ed354dc029c7f97bb4
This commit updates the EE repository reference after PR #709 was merged in windmill-ee-private.
Previous ee-repo-ref: 62f494b2a51de0dfc0cfa0c3530ff19a1d32667c
New ee-repo-ref: a45bec03922d305aad5893ed354dc029c7f97bb4
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* perf: serve the rare schedule options on demand instead of inlining them
* fix: let a real schedule argument win over a duplicate inside advanced
* fix: catch nested stripped schedule options and share the schema builder
* fix: check the whole schedule request for stripped options, not just advanced
* fix: do not point unknown schedule keys at the schema lookup
* fix: stop the chat deleting drafts as deployed workspace items
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep archived scripts deletable and defer malformed args to the schema
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: correct the delete/draft prompt claim and narrow the script probe catch to 404
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: bind the fork banner's comparison to the workspace it describes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: invalidate in-flight comparisons when leaving a fork
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop a CI summary fetched for a superseded comparison
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: anchor overlays to their host pane and mute them when hidden
* fix: portal hosted modals and menus into the pane they anchor to
* fix: keep non-listening dialogs off the overlay stack
* fix: drop the topmost gate from confirmation dialogs
* fix: silence overlays in a collapsed preview panel
* fix: keep overlays live in a full-screen preview of a collapsed session
* feat: azure workload identity auth for mssql and postgres resources
* refactor: keep mssql config lines untouched by the auth-mode change
* fix: single-flight token refresh, cache eviction and identity-aware pg cache key
* fix: back off after a failed entra id refresh and normalize blank pg identity fields
* fix: re-check the fallback token lifetime after a failed refresh
* refactor: select workload identity with a sentinel password instead of resource fields
* fix: log the workload identity mode on the postgres path too
* fix: stop reading a parent-only fork item as deleted in the fork
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* style: condense the deploy-direction helper comments
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the ambiguous half of a one-sided diff out of bulk defaults
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: disable select-all on a removal-only list and cover the hidden source-only row
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep parent-only items out of the fork merge list entirely
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: count the fork banner's ahead/behind with the compare page's predicate
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: open the direction the fork banner's button offers
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: cache the sqlx query for the source-only visibility test
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: don't read an unloaded comparison as nothing to deploy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: treat an in-flight comparison as unknown in the fork banner
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: auto-allow scratch file ops confined to /tmp
The /tmp entries in .claude/settings.json used a `Bash(cmd:/tmp/*)` form, but
the colon is only meaningful as a trailing `:*` wildcard — each was matched as
a literal command string no invocation produces, so mkdir, cp, mv, touch,
chmod, tar and unzip all prompted despite the rules being present.
mkdir and touch become working prefix rules. The rest move to a PreToolUse
hook, which is required for mv and chmod (both sit in the `ask` list, which
outranks any allow rule) and preferable for cp/tar/unzip: a prefix rule can
only constrain the first operand, so `cp /tmp/x ~/.zshrc` would match a
`cp /tmp/` prefix. The hook instead requires every path operand to resolve
under /tmp, which also keeps it from becoming a way around the
`Read(**/.env)` deny rules by copying a project file into readable scratch.
tar and unzip get a separate parser: their destination arrives as a flag value
(`-C`, `-d`) and a bundle like `-xzf` consumes the following token. Flags are
an allowlist, so `-P`/`--absolute-names`, which disable tar's refusal to
extract `..` and absolute member paths, defer rather than needing enumeration.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: close three symlink and prefix-rule escapes in the /tmp hook
Review findings on the previous commit, all three genuine:
Drop the `Bash(mkdir|touch /tmp/:*)` allow rules. A prefix rule constrains
only the first operand, so they accepted `mkdir /tmp/../etc/evil` and
`touch /tmp/a ~/.bashrc` — the hook already deferred both, but an allow rule
grants the call before the hook's silence can matter. They were also
redundant: the hook covers mkdir and touch on its own.
Refuse globs outright. Bash expands them only after the hook has decided, so
realpath saw the unexpanded pattern: `chmod 600 /tmp/link*` canonicalized to
itself, passed, then expanded onto a symlink pointing outside /tmp, and chmod
follows command-line symlinks. guard-rm-outside-tmp.sh can allow globs under
/tmp because `rm` unlinks a symlink rather than following it; every command
here follows one instead.
Make options a per-command allowlist. Generic acceptance let `cp -RL` through,
which dereferences while recursing and so copies the content of a symlink
target outside /tmp into a scratch dir that `Read(/tmp/**)` exposes — the same
deny-rule bypass the every-operand rule exists to prevent. Plain `-r` and `-a`
recreate such a symlink as a symlink and stay allowed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: require absolute operands so option words cannot pose as /tmp paths
Both remaining escapes shared a root cause: a token the tool reads as an
option was validated as a path, because resolving it against the cwd made any
bare word look safe whenever that cwd was under /tmp. `tar P -xf /tmp/a.tar
-C /tmp/out` checked out as /tmp/P while tar read P as --absolute-names, and
`cp /tmp/tree -RL /tmp/out` checked out as /tmp/-RL while cp read -RL as
dereferencing recursion.
Accept only absolute operands, which removes the class rather than the two
instances. Also apply the option allowlist at every position, since GNU utils
permute and recognize options after operands.
`unzip -l` no longer requires a destination; listing extracts nothing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: drop a contradictory comment and stop treating unzip -v as extraction
The sentence justifying the old before-first-operand option check outlived the
check itself, leaving the file asserting both that and the all-position rule
that replaced it. Only the second is true.
`unzip -v` is a verbose listing and writes nothing, so it no longer requires an
extraction destination.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: label session preview tabs by item summary when set
* feat: add hover title to session preview tabs
* fix: name unvisited session tabs from the workspace listing
* fix: retry a failed workspace listing for session tab labels
* fix: let a loaded editor supersede the listing name for its tab
* test: pin the editor-claims-tab ordering for session tab labels
* fix: show the fork banner to a superadmin who is not a workspace member
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: scope the non-member workspace cache to the current workspace
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: make the non-member workspace cache own exactly one workspace
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop the non-member workspace cache when no workspace is open
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: report why a native trigger service refused instead of a 500
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the cause of an unreachable trigger service in the message
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: degrade a trigger read only for the service's own failures
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: tell a refresh outage apart from a rejected refresh grant
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: treat a rate-limited or timed-out service as an outage, not a refusal
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep a token endpoint's status out of the trigger's
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: read a refused refresh grant off the body, not only the status
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: let a throttled 403 read as an outage, not a permission refusal
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: classify a refresh refusal by its OAuth code, and Google quotas by domain
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: recognize GitHub's other wording for a throttled request
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: return result.json and stdout results from sandboxed containers
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: capture unmasked stdout-only last line, validate container result.json
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: reject image WorkingDir that escapes the container root
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: verify the whole result mount destination against the extracted rootfs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: name the right skip reason and gate the symlink test to unix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: give dbt its own editor with an explicitly refreshed model graph
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: bump ee ref for the agent-worker dbt editor graph
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: scope editor graph retention by principal, carry parse context, honor nlang
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: bump ee ref
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the dbt editor's model graph and log panel mounted across tabs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the dbt_edge to dbt_node joins on an index-usable equality
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: poll a parse until the job ends, resolve the project key, correct the docs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: surface a slow parse's job, bound poll failures, drop banned bindable defaults
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: hide the dbt Generated UI content, not only its tab
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: honor disabled Triggers in the dbt tab fallback, record permissioned_as
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: one dbt pane with the run drawn on the models, and a full-height script graph
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: move the dbt build arguments behind the Build button
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: trim the dbt editor toolbar and stop the graph asserting a cause it lacks
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: mark dbt as alpha in the language picker and announce it once
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: trim the dbt alpha notice
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: give a selected dbt model the whole detail section, with a close that deselects
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: close the dbt detail panel by clicking away, and make its close obvious
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: cache the agent-worker dbt query, which needs the private feature to compile
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: never fall back to a settings tab the embedder disabled
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: preview dbt rows from the same project the graph was parsed from
* feat: hide the script-kind selector for dbt projects
* fix: pin a dbt row preview to the project its graph was parsed from
* fix: pin a dbt row preview to the arguments its graph was parsed under
* fix: keep dbt preview placeholders live while its vars stay pinned
* fix: report a warehouse-less dbt parse's counts and flag stale preview args
* fix: tell the pinned-vars case apart from a stale placeholder
* chore: update ee-repo-ref to 59044635769f18f8ff5073236cfc7b5f41e917cc
This commit updates the EE repository reference after PR #707 was merged in windmill-ee-private.
Previous ee-repo-ref: 7e424384cdd4cef8653b55b04f17ad3f801bc50c
New ee-repo-ref: 59044635769f18f8ff5073236cfc7b5f41e917cc
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* feat: add session recording to wmill app dev
* fix: harden dev recorder shell, bundle staleness guard and save route
* fix: keep dev-server recordings out of the raw app sync diff
* style: drop em dashes from new cli comments
* fix: tighten dev recorder save route origin, naming and io
* test: pin that only the root recordings folder is skipped
* fix: survive an oversized recording upload and match paths on windows
* fix: keep the app at the root and settle runnables stranded by a reload
* fix: make the recorder bundle hash stable on a crlf checkout
* docs: state the preflight-free content type the origin check guards
* test: build the sync-skip fixture with the platform separator
* docs: align the origin-guard test comment with the code
* chore: mark generated .gen.ts files as generated