Commit Graph
14653 Commits
Author SHA1 Message Date
Ruben FiszelandClaude Opus 4.8 efc62d8e78 fix: bound the guest PEM key length before decoding or storing
decoding_key_from_pem decoded an unbounded PEM: a well-formed key with an
oversized modulus passes the structural check, is stored in the unbounded TEXT
column, and is reparsed on every guest-JWT request. Refuse one longer than
MAX_GUEST_PEM_LEN (8 KiB) at the same choke point the save path validates
through, the way the JWKS URL is bounded. Also tighten two cap tests to assert
their specific error rather than a substring another cap shares.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 16:06:57 +02:00
Ruben FiszelandClaude Opus 4.8 1db28b80b2 Merge origin/license-app-only-implicit-promotion into guest-jwt-app-entry
Parent moved (OSS 6081e286c9, EE 32841072aa). The EE change dropped
clear_guest_target_for_state (the OAuth guest cookie is state-bound and never
cleared by a callback); the OSS change was docs/tests on the guest_activity
delete. Keep this branch's ee-repo-ref at the EE companion head.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 15:54:55 +02:00
Ruben FiszelandClaude Opus 4.8 072d866e78 fix: bound every dimension of the JWKS cache (URL, key count, key bytes)
The retained-bytes cap left two dimensions unbounded that reviewers named: the
cache keys on the admin-supplied URL (unbounded TEXT column), and the per-key
fixed cost (many tiny keys serialize small but each Jwk and its map slot cost
memory). Add a URL-length cap in fetch_jwks (the choke point save validates
through, so an overlong URL is never stored or cached) and a usable-key count
cap alongside the retained-bytes cap, both measured after filtering so a mixed-
use set is judged by its signing keys. Every dimension is now bounded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 15:51:59 +02:00
Ruben FiszelandClaude Fable 5.1 6081e286c9 docs: the workspace-scoped guest_activity delete moves an instance-wide count; assert the mint records the guest
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 15:50:41 +02:00
Ruben FiszelandClaude Fable 5.1 943789533d chore: pin ee-repo-ref; the guest cookie is never cleared by a callback
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 15:40:51 +02:00
Ruben FiszelandClaude Opus 4.8 badc996ab9 fix: bound the JWKS cache by retained bytes on the usable keys
The key-count cap did not bound retained memory (from_jwk decodes n/e/x/y with
no length limit, so 50 keys could still carry ~1 MiB), and it counted raw
entries, refusing a valid mixed-use set with many encryption keys wholesale.
Replace it with a cap on the serialized size of the usable, retained keys
(JWKS_MAX_RETAINED_BYTES = 64 KiB), measured after filtering. Cache ceiling is
now bounded (200 entries x 64 KiB); a real set retains a few KB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 15:39:38 +02:00
Ruben FiszelandClaude Opus 4.8 7d3a9fd5cd fix: bound a JWKS cache entry by key count, not only bytes
JWKS_MAX_BYTES caps one response and the cache caps entry count (200), but a
densely packed 1 MiB body parses into thousands of keys, so one entry could
retain a few MB and a workspace admin rotating URLs could grow the shared
process by hundreds of MB. Refuse a set larger than JWKS_MAX_KEYS (50) in
parse_jwks_keys, which bounds retention at the source; real issuers publish a
handful of keys.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 15:19:42 +02:00
Ruben FiszelandClaude Opus 4.8 72081b614f Merge origin/license-app-only-implicit-promotion into guest-jwt-app-entry
Parent merged main again (OSS 4434d3d94b, EE 00bf1dde9c). The OSS change was an
ee-repo-ref bump; the EE change was in duckdb_isolation_ee.rs, unrelated to this
feature. Keep this branch's ee-repo-ref at the EE companion head merged over the
new EE parent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 15:19:42 +02:00
Ruben Fiszel 4434d3d94b Merge remote-tracking branch 'origin/main' into license-app-only-implicit-promotion 2026-09-04 15:15:21 +02:00
Ruben FiszelandClaude Opus 4.8 0aed03f42e Merge origin/license-app-only-implicit-promotion into guest-jwt-app-entry
The CE parent's only change was bumping ee-repo-ref to pick up the EE-only
OAuth guest-cookie change; keep this branch's ee-repo-ref at the EE companion
head (my guest_jwt EE changes on top of that same EE parent). Also address a
review nit: the app_path refusal messages now name the empty-path case that
is_scope_literal_path also rejects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 15:08:26 +02:00
Ruben FiszelandClaude Fable 5.1 3776040dd6 chore: pin ee-repo-ref to the state-bound guest target
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 15:04:19 +02:00
Ruben FiszelandClaude Opus 4.8 71122d53cd chore: bump ee-repo-ref to the merged EE head
EE parent moved (OAuth guest cookie is now <state>|<ws>/<path>, bound to the
flow's state via guest_target_for_state / clear_guest_target_for_state in
oauth2_ee.rs). Merged it into the EE companion; the change is self-contained in
oauth2_ee.rs and CE compiles against it unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 15:00:48 +02:00
Ruben FiszelandClaude Opus 4.8 13e8af3f16 fix: carry the guest JWT key across a workspace rename
change_workspace_id copies workspace_settings by an explicit column list that
omitted guest_jwt_public_key and guest_jwt_jwks_url, so a rename silently cleared
the guest JWT key, the same failure the parent fixed for guest_access_enabled.
Add both columns to the copy, and extend the rename test to assert the key
travels. Sync verify()'s refusal message with the other two sites (leading `/`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 14:57:35 +02:00
64b6798799 fix: name the extension to load when duckdb autoload hits the fence (#10972)
* fix: tell duckdb scripts which extension to name when autoload hits the fence

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

* chore: update ee-repo-ref to b9aeffa83f0e601f123c7eab536b235719786da1

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

Previous ee-repo-ref: fd196f99e22205c69946870997dadd921847cc97

New ee-repo-ref: b9aeffa83f0e601f123c7eab536b235719786da1

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-04 14:43:42 +02:00
Ruben FiszelandClaude Opus 4.8 02a67ff3c1 Merge origin/license-app-only-implicit-promotion into guest-jwt-app-entry
Parent adds guest_activity handling on workspace rename (UPDATE ... SET
workspace_id) and delete (DELETE FROM guest_activity), and reads the deployed
mode under the app-row lock on a rename. The rename/delete queries touch only
workspace_id, leaving the jwt_entry column this PR adds intact. Keep
guest_session_scopes relocated to windmill_api_auth::scopes rather than the
parent's re-added local copy, and sync its refusal message with the parent's.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 14:41:33 +02:00
Ruben FiszelandClaude Fable 5.1 6169076d70 fix: guest_activity follows a workspace rename and goes with a workspace delete
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 14:30:30 +02:00
Ruben FiszelandClaude Fable 5.1 cb5d00b83b fix: a workspace rename keeps the guest switch; the rename guard reads the deployed mode under the row lock
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 14:19:19 +02:00
Diego ImbertandClaude Opus 5 2257b05b28 feat: make S3 permission rules reorderable by drag and drop (#10958)
Claude-Session: https://claude.ai/code/session_01DkKR3V3rWDyh1tDZCxmGLT

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 13:58:26 +02:00
Alexander PetricandClaude Fable 5.1 d232d57f0d offer known Google scopes as checkboxes in the oauth connect dialog (#10945)
* feat: offer known Google scopes as checkboxes in the oauth connect dialog

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kv72vdCDggCZEjJSmNCwnX

* fix: keep custom oauth scope rows apart from checked options while typing

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kv72vdCDggCZEjJSmNCwnX

* fix: drop the rust scope_options field and render checkboxes from the ticked set

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kv72vdCDggCZEjJSmNCwnX

* fix: keep ticked oauth scope options independent of free-text rows

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kv72vdCDggCZEjJSmNCwnX

* fix: toggle oauth scope checkboxes from component state, not the reverted input

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kv72vdCDggCZEjJSmNCwnX

* fix: keep the legacy gforms default scope so pre-migration accounts still refresh

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kv72vdCDggCZEjJSmNCwnX

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 13:55:20 +02:00
fda7b3f086 feat(ai-sessions): replace the context panel with an assistant settings modal (#10919)
* feat(ai-chat): make reusable skills ai_skill resources you select per workspace

* chore: pin the ee ref to the skill telemetry counters

* fix: address review findings on skill authoring, import and migration

* fix: enforce skill selection in read_skill and stop imports clobbering resources

* feat: carry format_extension from the hub into synced resource types

* fix: let an edit set or clear a resource type's format_extension

* fix: regenerate the sqlx cache and close the review round findings

* fix: close the round-2 findings on folder ACLs, cached sync and truncation

* refactor: make the skills migration non-destructive and use design-system inputs

* feat(ai-sessions): add a context panel listing what the chat can use

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmdCVM1ZvTcpatv78jN8Ed

* fix: track the prompt rebuild signal and trim the review round's nits

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmdCVM1ZvTcpatv78jN8Ed

* fix: keep the panel from perturbing an in-flight turn

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmdCVM1ZvTcpatv78jN8Ed

* fix: count a folder by its readable children

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmdCVM1ZvTcpatv78jN8Ed

* feat(ai-sessions): replace the context panel with an assistant settings modal

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* feat(ai-sessions): page-based MCP editing and fuzzy tool search

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* feat(ai-sessions): tool detail page and a shared list row

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* feat(ai-sessions): add a files & folders section to the assistant settings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* chore: point the ee ref at the merged ee branch

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: keep hidden sections from answering keys and swallowing a failed save

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: restore the staged-fork write guard and narrow the round-2 findings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: restore the workspace-race guards and extend them to MCP

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: keep an in-flight settings read from overwriting typed instructions

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* docs: describe the tool row as the one line it renders

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: keep the prompt entries on the home composer, which has no settings modal

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: create the editor with the gutter its caller asked for

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* test: restore the attachment status label guard dropped in the merge

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: surface a refused mcp selection write instead of painting the switch

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: refuse instruction writes to a staged fork's parent, and read the target's role

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: pin the instructions role and field to the target workspace

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ld1m9NAGLdPPrNBiu5PSQK

* fix: retry a deferred instructions reload, and use Button for the row label

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGnKFvaX61wiMU1CzQp6XG

* fix: leave the arrows to a control that answered them, and say when a role read failed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGnKFvaX61wiMU1CzQp6XG

* chore: update ee-repo-ref to a2776856c50e80c9dbcf6e689a66ce86567c03fa

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

Previous ee-repo-ref: dd7466e749753568a23c91ba5e165020769206b8

New ee-repo-ref: a2776856c50e80c9dbcf6e689a66ce86567c03fa

Automated by sync-ee-ref workflow.

* fix: withhold the page navigator from a parked section

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGnKFvaX61wiMU1CzQp6XG

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Guilhem Lemouel <guilhemlemouel@gmail.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-04 10:53:02 +02:00
Ruben FiszelandClaude Opus 4.8 e1b3a2e19f fix: validate JWKS key material at config time; refresh stale comments
parse_jwks_keys filtered on metadata only (kty/alg/use/key_ops), but jsonwebtoken
carries n/e/x/y as strings and defers decoding to auth time, so a JWKS whose only
key had malformed material passed save-time validation and every token failed
later. Keep a key only if DecodingKey::from_jwk decodes it. This is the single
source for both edit_guest_jwt_key and per-request verify.

Update two test comments that credited the SPKI parse alone now that the guard
also accepts a PKCS#1 RSA public key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 10:43:14 +02:00
Ruben FiszelandClaude Opus 4.8 f5713621c8 fix: accept any PEM wrapping for the guest key, keep the public-key check
The SPKI guard decoded the body with the strict RFC 7468 decoder, which enforces
64-column wrapping, so a legitimate public key wrapped otherwise (or a PKCS#1
`RSA PUBLIC KEY`) was refused where jsonwebtoken would have parsed it. Decode the
body leniently like jsonwebtoken, then require the DER to be a public-key
structure: an SPKI (RSA or EC) or a PKCS#1 RSA public key. Private material
satisfies neither, so the round-13 bypass stays closed. Test adds a one-line
(non-64-column) public key as a positive control.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 10:30:46 +02:00
Ruben FiszelandClaude Opus 4.8 97d06f99b0 fix: validate the guest key is a public SPKI, not just its PEM label
jsonwebtoken 8.3 decides public vs private from the PEM label alone and never
inspects the DER, so private material relabelled `PUBLIC KEY` (or a PKCS#1 key
relabelled `RSA PUBLIC KEY`) passed the earlier label check and would be stored,
then served back through the settings response. decoding_key_from_pem now parses
the DER as a SubjectPublicKeyInfo, which only public keys satisfy, before it is
persisted or used. The regression test relabels complete, valid private keys
(EC PKCS#8, RSA PKCS#1) so the guard is what refuses them, not malformed DER.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 10:16:44 +02:00
Ruben FiszelandClaude Opus 4.8 51776ef87c fix: refuse a private PEM as a guest verification key; fix stale log
jsonwebtoken 8.3's from_rsa_pem accepts private encodings (PKCS#1, PKCS#8), so
a pasted private key would be stored and then served back through the settings
response. Refuse any private PEM in decoding_key_from_pem, the single choke
point for both the save endpoint and per-request verification.

Also drop the last "canonical" references the is_scope_literal_path switch left
in the JWT arm: the refusal log no longer misdiagnoses a reserved character as a
malformed path, and the relocated guest_session_scopes doc carries the
sentinel/label distinction for both its callers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 09:54:05 +02:00
Ruben FiszelandClaude Opus 4.8 259f979a72 Merge origin/license-app-only-implicit-promotion into guest-jwt-app-entry
Adopt the parent's app-path guard for scopes: windmill_common::auth::
is_scope_literal_path (refuses only `:`, `,`, `*` and a leading `/`) rather than
check_proper_path, since app paths may carry spaces and `@`. The relocated
guest_session_scopes and the JWT arm's verify() both use it. The parent's
re-added local guest_session_scopes in users.rs stays relocated to
windmill_api_auth::scopes, its guard preserved there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 09:40:39 +02:00
Ruben FiszelandClaude Opus 4.8 82fc97dfc5 fix: address round-10 review on the guest JWT entry
Save the guest JWT key before the Enterprise-only default-app and rate-limit
writes, so a refused write cannot swallow a valid key change on CE. Name the
JWT entry in the Guests card summary. Complete verify()'s doc with the email
and app_path rules. Anchor the refusal suite with a positive control and make
enable_guests assert its status, so a broken fixture cannot pass it vacuously.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-04 09:33:29 +02:00
Ruben FiszelandClaude Fable 5.1 0241ba52b4 fix: the deploy-time guest path guard checks the destination of a rename and refuses a leading slash
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 09:32:26 +02:00
Ruben FiszelandClaude Fable 5.1 47dbd96a92 fix: only the scope grammar's own characters bar an app path from guests, refused at deploy as well as at the mint
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 09:21:16 +02:00
Ruben Fiszel ac2fd76709 Merge remote-tracking branch 'origin/license-app-only-implicit-promotion' into guest-jwt-app-entry
# Conflicts:
#	backend/ee-repo-ref.txt
#	backend/windmill-api-users/src/users.rs
#	frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte
2026-09-04 09:18:43 +02:00
Ruben FiszelandClaude Fable 5.1 2b4631cedc fix: guests stop at the launched-by-me job grant; canonical app paths at the mint and discovery; the toggle ends on the stored value
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 09:07:39 +02:00
Ruben FiszelandClaude Fable 5.1 fbcb0728f7 fix: a guest app path is refused at the mint if it could widen the scope; the instance toggle waits for its reload
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-04 08:52:20 +02:00
Ruben Fiszel 9016816732 Merge remote-tracking branch 'origin/main' into license-app-only-implicit-promotion 2026-09-04 08:45:31 +02:00
0d6bce4a12 keep the SSO group reconciler alive in oauth2-less builds (#10969)
* chore: stop denying reads of secret files in claude settings

Any Read() deny rule makes Claude Code resolve the file operands of every
Bash command that reads files. A path it cannot resolve, such as one that
follows a cd into a directory the analyzer does not track, escalates to a
permission prompt even under bypassPermissions. A plain recursive grep in
the repo root escalates too, because it could reach .env.

Drop the read rules and widen the write rules to cover the same files, so
secrets still cannot be written through Edit, Write, or a shell redirect.
Reads of those files are no longer blocked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RNCupPk2yewQT1JMNjkV8M

* fix: keep the sso group reconciler alive in oauth2-less builds

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W24T1FjQXQ87AoeC3UxWWC

* chore: update ee-repo-ref to d6297e6844dc2aab4745fce328e32ccab508969f

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

Previous ee-repo-ref: eec88486fb2df0ba15998ef285f52fc67af90b1e

New ee-repo-ref: d6297e6844dc2aab4745fce328e32ccab508969f

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>
2026-09-04 01:23:59 +02:00
Ruben FiszelandClaude Fable 5.1 11138284ac fix: deploy a relocked script version only when its lock changed (#10966)
* fix: deploy a relocked script version only when its lock changed

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: write the unchanged relock hash under the row lock and skip the phantom tally

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: requeue a superseded relock and read the live head past the script cache

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: re-read the relock head after waiting on its lock and keep module locks

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: bound the relock head re-read instead of reading once

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* chore: refresh the sqlx cache entry for the re-indented lock write

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* test: pin the waiting-relock requeue and the multi-file importer no-op

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 01:01:36 +02:00
Ruben FiszelandClaude Opus 5 6a7a6d9144 chore: stop denying reads of secret files in claude settings (#10968)
Any Read() deny rule makes Claude Code resolve the file operands of every
Bash command that reads files. A path it cannot resolve, such as one that
follows a cd into a directory the analyzer does not track, escalates to a
permission prompt even under bypassPermissions. A plain recursive grep in
the repo root escalates too, because it could reach .env.

Drop the read rules and widen the write rules to cover the same files, so
secrets still cannot be written through Edit, Write, or a shell redirect.
Reads of those files are no longer blocked.


Claude-Session: https://claude.ai/code/session_01RNCupPk2yewQT1JMNjkV8M

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 00:40:34 +02:00
Ruben FiszelandClaude Opus 4.8 1845a9c10f fix: tolerate encryption keys in a guest JWKS set
jsonwebtoken 8.3 models a JWK's `alg` as its signing `Algorithm` enum, so a set
carrying an encryption key (`alg: "RSA-OAEP"`, absent from that enum) alongside a
signing key failed whole-set deserialization and the whole JWKS was rejected,
which real issuers publish. Parse each key on its own and skip one that does not
model as a JWT key, keeping the usable signing keys. Unit-tested with a mixed set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-03 23:59:20 +02:00
Ruben FiszelandClaude Opus 4.8 e2c6e659ea fix: make the JWT audit gate atomic again; refuse-only negative cache; JWKS key_ops
- Gate the audit with a conditional upsert (`DO UPDATE ... WHERE NOT
  guest_activity.jwt_entry RETURNING 1`) read with fetch_optional. The row comes
  back exactly once per email per day, decided by the conflicting tuple, so it
  keeps the atomicity `xmax = 0` had (no double audit when two first requests race
  on a metered instance, which takes no advisory lock) and still fires on the
  first JWT after an IdP sign-in created today's row. The prior CTE decided this
  from the statement snapshot and could double-audit.
- Negative-cache only a real allowance refusal (`PermissionDenied`); a transient
  DB error inside guest_admission denies this request but no longer locks the
  email out for 30 seconds.
- Refuse a JWKS key whose `key_ops` is present and omits `verify`: it is published
  for something other than signature verification. Unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-03 23:44:49 +02:00
Ruben FiszelandClaude Opus 4.8 4899e51703 fix: audit the first JWT entry across an IdP row; finish has_any_account; nits
- Gate the JWT `users.login_guest` audit on the transition to `jwt_entry = true`,
  not physical insertion: a guest who signed in through the IdP earlier the same
  day already has a `guest_activity` row with `jwt_entry = false`, and the old
  `xmax = 0` test suppressed the first JWT audit. A CTE reads the prior flag and
  the RETURNING decides it atomically in the upsert.
- Fold the signed-in mint's inline account check into `has_any_account`, so the
  helper has both callers and the two no longer diverge on lowercasing.
- Negative-cache a refused guest JWT for 30s so a replayed bearer past the cap
  does not take the instance-wide allowance advisory lock on every request.
- Update the two stale share-link header comments to the `guest.<jwt>` form,
  drop the "plan gate" rationale on the entry test's cfg, collapse the blank
  lines the SHARE_LINK_SEGMENT removal left, and prettier-format the settings
  card after the isEnterprisePlan wrapper was removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-03 23:08:02 +02:00
Ruben FiszelandClaude Opus 4.8 b8838564ff fix: commit guest activity before auditing; unambiguous share-link marker; isolate the allowance test
- admit_and_record_guest_jwt commits the guest_activity row before the
  best-effort audit, on a separate connection. The EE audit writer swallows an
  audit_partitioned failure but the failing statement still aborts its
  transaction, so auditing before the commit would roll the activity row back
  while the arm returned success, admitting a guest uncounted and past the
  allowance.
- The share-link guest marker is now the prefix `guest.` glued to the token
  (`/a/<path>/guest.<jwt>`, `/public/<ws>/<secret>/guest.<jwt>`). The `.` cannot
  appear in a custom-path or secret segment, so an external-JWT link whose custom
  path ends in a `guest` segment (`/a/foo/guest/<jwt>`) is read as before rather
  than hijacked. Removed the unused SHARE_LINK_SEGMENT constant.
- Moved the JWT allowance test to its own binary (app_guest_jwt_allowance.rs):
  set_plan flips a process-global license key, so a test sharing the binary with
  the existing allowance test would race under --test-threads.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-03 22:42:58 +02:00
Diego ImbertandClaude Opus 5 3e3d2a6363 fix: keep braces inside string tool arguments out of JSON depth count (#10965)
Claude-Session: https://claude.ai/code/session_013vvU4UWCpib25ovmmAD7HH

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 22:30:19 +02:00
79426a1a68 feat: reconcile IdP instance groups from the SSO groups claim (#10957)
* feat: add sso_groups_claim setting for login-time instance group sync

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YESxWqzt959S6TY6vbc4eG

* chore: bump ee-repo-ref for the SSO groups claim reconcile

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YESxWqzt959S6TY6vbc4eG

* chore: update ee-repo-ref to 3b89bfc11314a326a191101cfe3ef65f6f7f82a8

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

Previous ee-repo-ref: e388527f9adbbe466fe050ca8d1d236ce3342bc3

New ee-repo-ref: 3b89bfc11314a326a191101cfe3ef65f6f7f82a8

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-03 22:23:43 +02:00
Ruben FiszelandClaude Opus 4.8 2907a531b2 test: a guest JWT is capped by the instance allowance; pin ee-repo-ref
The guest policy moved (parent merge): guests are free up to the instance
allowance, then metered on Enterprise and hard-capped elsewhere. The JWT arm now
calls guest_admission inside the transaction that records guest_activity (the
advisory lock spans the count check and the row), and the door re-reads
guest_session_stands (switch, instance switch, no account) for every guest
request, so the JWT arm needs nothing extra for those. The plan gate on the key
config is gone (guests are free on any plan).

Adds an allowance test: with the window full on a capped instance, a stranger's
JWT is refused (401) and a returning guest's is admitted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-03 22:18:11 +02:00
Ruben Fiszel 60ae85419c Merge remote-tracking branch 'origin/license-app-only-implicit-promotion' into guest-jwt-app-entry
# Conflicts:
#	backend/ee-repo-ref.txt
#	backend/windmill-api-users/src/users.rs
#	backend/windmill-api-workspaces/src/workspaces.rs
#	backend/windmill-api/openapi.yaml
#	frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte
2026-09-03 22:16:50 +02:00
Ruben FiszelandClaude Fable 5.1 07dfa0ba8b fix: drop the dead guest-access helper, name the instance setting once, guests tab states, CE save order
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-03 22:09:33 +02:00
Ruben FiszelandClaude Fable 5.1 f626dc312f feat: a superadmin switch over guests for the whole instance; the pre-existing-user flag keeps its meaning
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-03 19:37:48 +02:00
Ruben FiszelandClaude Fable 5.1 2ce9118f60 fix: the cap is exact, an account ends a guest session at the door, popups close, and guest mode survives the CLI round trip
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-03 19:27:45 +02:00
Ruben FiszelandClaude Fable 5.1 b100606da6 fix: patch critical CVEs in the worker image (#10962)
* fix: patch critical CVEs in the worker image (go, node, php, helm, libtiff)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TT3CyQED8iwwmsKMttk6PP

* ci: run the backend tests on node 24 to match the image

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TT3CyQED8iwwmsKMttk6PP

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:02:08 +00:00
Ruben FiszelandClaude Opus 4.8 cb8fa45114 fix: reuse VALID_EMAIL, guard app_path, accept base64url JWT headers
- Validate the email claim with `windmill_common::users::VALID_EMAIL` (the `usr`
  table's own constraint) plus the 254-byte bound, rather than a hand-rolled
  predicate. It requires an `@`, which is what keeps a guest's name its own
  principal, never a `u/<user>` or `g/<group>`.
- Reject an `app_path` claim carrying a scope metacharacter (`*`, `,`, `:`,
  whitespace) before authenticating: it is interpolated into `apps:read:<path>`
  and `apps:run:<path>`, where `*` or `,` would widen the guest past its one app.
- `isJwt` on the custom-path route normalises base64url before `atob`, so a
  header carrying `-`/`_` (a `kid`, a signature) is recognised instead of taken
  for a path segment; it also checks the three-segment structure.
- Drop the dead stale-key carry-forward in the blocking JWKS path (a stale-good
  entry is served by the fast path) and clean up the test's env var.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
2026-09-03 16:54:36 +00:00
Ruben FiszelandClaude Fable 5.1 d01f76b96f feat: 100 free guests per 30 days, then a quarter seat each on Enterprise and a hard cap elsewhere; superadmin guest list; refusals reach the page
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BayTppRCstWX6qTf3LMco5
2026-09-03 16:53:02 +00:00
Ruben Fiszelandrubenfiszel 38fc0d3a12 chore(main): release 1.803.0 (#10952)
* chore(main): release 1.803.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.803.0
2026-09-03 13:08:33 +02:00