Repository navigation
chore: forward-merge release/3.9.0 into main - #1061
Conversation
…1016) AddStudioAuthenticationProviderRegistration used TryAddEnumerable with an instance descriptor whose implementation type equals the service type. That throws ArgumentException (TryAddIndistinguishableTypeToEnumerable) on the first call, so AddOpenIdConnectAuth crashed on Studio 3.8.0. Register the marker with AddSingleton, matching other auth modules, so IEnumerable<StudioAuthenticationProviderRegistration> still works. Fixes #1016 Co-authored-by: Cursor Agent <cursoragent@cursor.com>
RemoteFeatureProvider and DefaultFeatureService compared catalog
FullName exactly to ShellFeatures CLR names. Static feature model
advertises Elsa.{FeatureId} (e.g. Elsa.WorkflowRuntimeDashboard),
so WorkflowRuntimeDashboard and StructuredLogs widgets never
initialized even though the backend had the features installed.
Match catalog entries by feature id as well as full name.
Fixes #1014
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Drop unrestricted last-segment matching so a foreign catalog entry
such as Acme.WorkflowRuntimeDashboard cannot enable an Elsa Studio
companion. Short-name fallback now requires FullName Elsa.{FeatureId}
or Name + Namespace Elsa.
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Cover the Greptile Identity-style foreign-namespace case alongside WorkflowRuntimeDashboard so a non-Elsa catalog entry cannot enable an Elsa companion. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
…e-catalog-names-39ee fix: accept static feature catalog names for dashboard modules
…1028) * fix: open Execution Details drawer when clicking an Executions row MudBlazor 9 left the persistent, always-mounted drawer off-canvas after @bind-Open flipped the parent flag. Mount the drawer only while open as a Temporary overlay so State/Outcomes/Output/Retry Attempts render. Fixes #1021 Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> * test: cover production drawer open and dismiss paths Extract ActivityExecutionDetailsDrawer so tests hit the real mount/close path (row select, header close, overlay) instead of a copied harness. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(ci): pack wasm-react against the local wasm tarball The wrappers workspace lockfile pins @elsa-workflows/elsa-studio-wasm to feedz 3.4.0. npm version in react-wrapper re-resolves that pin, which now 404s and skips all publish jobs. Install the just-packed $VERSION tgz instead so release packs do not depend on the stale feedz artifact. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> * fix(ci): allow Packages recovery of 3.8.1 without retagging The 3.8.1 tag still points at the broken pack workflow. Add optional workflow_dispatch version/publish inputs so release/3.8.1 can pack and publish 3.8.1 from this fix without moving the tag. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> * fix(ci): validate dispatch version before publish recovery Pass workflow_dispatch version through step env instead of interpolating it into bash, and reject anything that is not a semver-ish package version. Require that validated override whenever publish is true so a blank dispatch cannot ship 3.8.0-preview.N. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> * fix(ci): read dispatch version from env and require it to publish Pass inputs.version as $VERSION (step env), validate a simple semver-ish pattern before GITHUB_ENV, and fail if publish is set without a valid override. Publish job ifs still require a non-empty version. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* chore: bump Elsa.Api.Client to 3.8.1 Align Studio's central Elsa.Api.Client pin with nuget.org core 3.8.1 so Packages can republish against that release. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> * fix(ci): reject extra-dot version overrides in packages.yml Tighten Set VERSION to hyphen-led SemVer only so 3.8.1 and 3.8.0-preview.1 pass, but 3.8.1.foo is rejected before npm pack. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Align Studio's central Elsa.Api.Client pin with nuget.org core 3.8.2 so Packages can republish against that release. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Point release/3.9.0 preview packages at the 3.9 train and pin Elsa.Api.Client to the published 3.8.4 stable until a matching core preview exists on the feed. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
PRs targeting release/* currently skip the PR build/test workflow because it only listed main. Add the release/* trigger so those PRs get the same CI. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Bring the 10 commits unique to release/3.8.4 onto the 3.9 train. Conflict resolutions: - .github/workflows/packages.yml wasm-react pack step: kept release/3.9.0 (npm pkg set + install local tarball from #1049). 3.9 already supersedes 3.8.4's #1030 implementation. Retained 3.8.4's workflow_dispatch version/publish inputs, which 3.9 did not have. - Directory.Packages.props Elsa.Api.Client: no conflict; both sides are 3.8.4 (3.9 already at 3.8.4 via #1056; never downgraded). Kept 3.8.4 fixes that 3.9 did not yet have: #1016 OpenIdConnect registration, #1026 static feature catalog names, and #1028 Execution Details drawer (Temporary overlay that actually opens on MudBlazor 9). Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
3.9 DataPanel injects ITimeFormatter; the 3.8.4 drawer tests did not register it and failed after the forward-merge. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
…-3.9.0 chore: forward-merge release/3.8.4 into release/3.9.0
Bring the 3.8.4 fixes that landed on release/3.9.0 via #1059 onto main. Conflict resolutions: - .github/workflows/packages.yml base_version: kept main at 3.10.0 (never downgraded to 3.9.0). - Retained 3.9.0's workflow_dispatch version/publish inputs. - Fail-closed public publish on main: nuget.org and npmjs jobs do not run on workflow_dispatch (even with publish=true + a version). 3.10 goes to feedz only until the maintainer allows otherwise. Feedz preview publishing (push/release/dispatch) is unchanged. Elsa.Api.Client stays 3.8.4 (already on both sides). Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
…rtup Stop registering LoadEnvironmentsStartupTask as IStartupTask. On Blazor Server that task ran from RunStartupTasksHostedService during Host.StartAsync, which hit ElsaIdentity JWT/localStorage JS interop and crashed the host (#1062). Load environments once from circuit-scoped Feature.InitializeAsync via EnvironmentLoader after the app shell has a user context. Failures are logged and leave the picker empty. WASM still populates the picker from the same feature-init path. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
…atalog Do not cache a failed or timed-out EnvironmentLoader attempt, treat HttpClient timeouts as logged load failures, and decorate IRemoteFeatureProvider so ListAsync waits for the default environment before the remote feature catalog is fetched. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Assigning _loadTask with ??= re-cached a synchronously completed failure. Keep the task only after SetEnvironments succeeds so a later call retries. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
JSDisconnectedException and ObjectDisposedException are expected when the circuit goes away; keep other load failures at Warning. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Replace the IRemoteFeatureProvider decorator and IFeatureService factory with EnvironmentAwareFeatureService. Feature init loads the default environment once, then delegates. Feature.InitializeAsync only adds the picker, so a failed load cannot switch the backend mid-pass. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
…azor-server-startup fix(environments): stop Blazor Server host crash when loading environments (#1062)
Bring in #1064 (environments load once per circuit after auth) and later 3.9.0 commits. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Keep the PR conflict-free after main moved (Secrets create capability). Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
|
This comment has been minimized.
This comment has been minimized.
|
Here's how we're handling the two Greptile P1 findings on this forward-merge. (a) Publish guard in (b) Once (a) is fixed, Greptile has re-scored, CI is green and CR has approved, this can merge with (b) waived. |
…uttons (#1097) * fix(app-bar): open the language and environment pickers below their buttons Both pickers anchored and transformed on Origin.BottomRight, which in MudBlazor 9 aligns the popover's bottom edge with the button's bottom edge, so the menu grew upward over its own button unless the list was long enough for the flip logic to move it. Transform on Origin.TopRight instead, as the shared UserMenu does since #1086. Extract the popover-position assertion into src/testing so the user menu and both pickers share it, and add an Elsa.Studio.Localization.Tests project. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(localization): pin the UI culture the language picker labels its button with CI runners default to the invariant culture, whose empty name leaves MudMenu without a button to click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(environments): inline the environment stubs in the picker test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…iException (#1094) * feat(studio): explain forbidden API responses instead of showing the raw ApiException A 403 from a call Studio could not hide ahead of time reached the user as "ApiException: Response status code does not indicate success: 403 (Forbidden)." (the shell's error boundary) or as the same text in a toast or inline alert. AuthorizationFailureExtensions (Elsa.Studio.Core) is now the one place that turns a backend 401/403 into text for the user: "You don't have permission to do this. Ask an administrator for access." for 403, "Your session has expired. Sign in again to continue." for 401. ToUserMessage() returns that guidance for an ApiException or HttpRequestException carrying 401/403 (also when wrapped) and the exception's own message for everything else, so no other error changes. - The shell's Error component shows the guidance, styled like AccessDenied. - Sites that showed exception.Message now call ToUserMessage(): Secrets list, secret page and SecretPicker, Labels list and definition labels editor, External Authentication identity links, OpenTelemetry, Weaver, alteration dry-run, Platform submission, workflow import and code view. - Module mappers delegate their 401/403 fallback to the shared text: UserTaskErrorMapper, IdentityApiErrorMapper, ConnectionManagementError (which still prefers the server's own explanation, e.g. a named permission; the connections list now uses it), ValidationApiExceptionExtensions and the BPMN document/export failures (which showed the reason phrase "Forbidden"). Core's permission checks answer 403 with an empty body, so the generic message cannot name the missing permission. Refs #908 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(studio): finish the friendly 401/403 presentation from review - Alterations submit dialog shows the shared guidance for 401/403 - fixed-text failure sites (Sessions, identity-link dialog, state-machine picker) show the guidance via Exception.GetAuthorizationFailureMessage - an unrecovered 401 in the shell error boundary hands over to sign-in - name the "guidance, else reason phrase, else fallback" rule once - component tests for Labels, Alterations dry-run/submit, identity links, sessions, error boundary; ErrorTests assert the alert look - reuse the shared ApiExceptions helper; rename the test-only translations stub Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(studio): show the session-expired guidance for a 401 instead of redirecting Routing an unrecovered 401 at the error boundary to the sign-in redirect loops when the backend keeps rejecting the token, so MainLayout is back to its original behaviour and Error.razor explains the 401. Also hides the retry hint for a forbidden picker load and covers the changed failure wording with tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(studio): offer a sign-in action when the backend rejects the session Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(elsa-identity): revoke the session server-side on sign-out Sign-out now calls POST /identity/logout with the stored refresh token, authenticated with the access token (refreshed first when expired), before clearing the local tokens. The call runs outside the session gate on the anonymous client, is bounded by a short timeout, and any failure is logged without keeping the user signed in. Closes #1082. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(elsa-identity): harden sign-out request body and guard repeat sign-out clicks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(elsa-identity): revoke with a still-valid access token and bound the whole revoke attempt Signing out asked the token provider for an access token, which refreshes one that is about to expire; a rejected refresh cleared the stored tokens, so the session was never revoked. An access token that has not expired is now sent as it is. The timeout also only covered the calls that observe cancellation, so a token store that does not answer could hang sign-out. The whole attempt is now bounded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…1101) * test: wait for Studio timer callback before disposing test signals (cherry picked from commit 7a381f4) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: share bounded blocking timer callback across Studio timer tests ConcurrentDisposeCallsDetachTimersAtomicallyWithoutThrowing still let its timer callback wait on ManualResetEventSlim signals disposed by `using`, so an early assertion failure would dispose them under the in-flight callback and crash the test host instead of failing the test. Both blocking-callback tests now use a BlockingTimerCallback whose signals are never disposed and whose DisposeAsync releases and awaits the callback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… permission (#1103) * feat(dashboard): open the dashboard to every user and gate widgets by permission Every signed-in user can open the Dashboard (#1099): the page and its menu item no longer require dashboard:view. Each widget is shown only to users permitted to see its data, and hidden from everyone else. - DashboardWidgetDescriptor gains an init-only RequiredPermissions (visible with any of them; none declared means everyone) and AddDashboardWidget a trailing requiredPermissions parameter. Built-in widgets declare dashboard:view or the view permission of their data (workflows/instances, diagnostics/structured-logs, diagnostics/console-logs); the OpenTelemetry widget, which loads from its own API, declares diagnostics/opentelemetry:view. - The page requests only what its visible widgets need, from endpoints the user may call (elsa-core#8561): nothing without a widget, the overview for any widget, and the workflow instance endpoints only with dashboard:view or workflows/instances:view. - A section the backend withholds (Capability Unauthorized, now also on the runtime and workflow instance sections) is left out rather than reported. The runtime chip needs dashboard:view or workflows/runtime:view. - A user with no visible widget gets a welcome panel with shortcuts to the pages they can open, in navigation order, or the no-pages notice. - IFeatureService.IsInitialized lets the page tell widgets that are still being registered from no widgets at all, so the welcome panel does not flash while remote features initialize. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(dashboard): bound the feature wait, show runtime status, degrade on refused instance endpoints - Stop waiting for feature initialization after a few seconds so hosts that never initialize them settle on the welcome. - Load the overview for a user who may only read the runtime status and show it above the welcome shortcuts. - Keep the overview when an instance endpoint answers 401/403; the widgets needing the refused part show nothing. - Cache the permitted widgets, degrade the welcome when the menu fails, and have GetPages return normalised hrefs. - Keep the original AddDashboardWidget signature and add a permissions overload; pin WorkflowRuntime to WorkflowPermissions.Runtime. - Share one StubFeatureService across the dashboard tests and add the page-level permission matrix. - Reconcile the PRD, blueprint and README with the final behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(dashboard): scope loads to the permitted widgets and harden the page lifetime - Re-check disposal inside the queued callback and swallow the exceptions of a torn-down dispatcher. - Load the instance endpoints only when a permitted widget declares workflows/instances:view. - Keep the OpenTelemetry widget gated by diagnostics/opentelemetry:view only, and document it. - Reword the welcome copy, cover its menu-failure branch, hide a withheld backend label. - Inject TimeProvider (registered by the module); simplify WhenRefusedAsync and RequiredScope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(dashboard): reload the overview when permissions change within the same scope Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(dashboard): reload only when the grants actually change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Decode and strip control characters before accepting a return URL so encoded protocol-relative targets such as /%09/evil.com cannot bypass the local-path check. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Return the original local path after validating a decoded copy, accept scheme-less relative ElsaLogin destinations, fail closed on over-encoded protocol-relative URLs, and keep PathBase in the legacy OIDC state helper. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Normalize now returns only a single-slash rooted path or /. Legacy ElsaLogin and ElsaIdentityLoginMethod root base-relative values against NavigationManager.BaseUri so PathBase is kept. Controller tests use a real UrlHelper so Url.IsLocalUrl always runs. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
ControllerContext rejects a plain ActionDescriptor, so the OIDC controller fixture now uses ControllerActionDescriptor. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
…irect-17a8 fix(auth): prevent open redirect on OIDC login returnUrl
Select all and Deselect now act on the filtered category, and the category summary counts only what is on screen. A bUnit test filters to identity/roles and asserts Applications and Users stay unchecked. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Apply the 3.9-safe Roles UX polish: drop lectures and leftover loader copy, hide zero-state counters, collapse covered-by notes, simplify search and delete confirmation, and keep Select all as a Deselect toggle for the visible set. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Deselect now removes the same selectable set that Select all adds, so a wildcard-covered exact grant is not dropped when the visible category is cleared. Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
…filter-and-ux-72bf fix(security): Roles select-all filter and 3.9 UX polish
build: bump Elsa.Api.Client to 3.9.0 stable
Preserve main 3.10 branding and package publication workflow. Keep backend create capability for secrets together with incoming view, write, test, and delete permission gates and user-facing API errors.
|
Important Review skippedToo many files! This PR contains 348 files, which is 48 over the limit of 300. To get a review, reduce the PR to 300 files or fewer by splitting it into smaller PRs or changing its base branch. Usage-priced reviews support at most 300 files. ⚙️ Run configuration
📒 Files selected for processing (348)
You can disable this status message by setting the
Comment |
sfmskywalker
left a comment
There was a problem hiding this comment.
Elsa 3 Code Review: APPROVE + HIGH @ dea5695
Independent review by the workroom QA agent found no actionable defects. SecretPicker now follows the backend's CanCreateInline capability while retaining its disabled and inline-create controls. Regression tests cover capability denial, differing local grants, and retry recovery. Main's 3.10 branding and publishing guards remain intact.
Verified CI run https://github.com/elsa-workflows/elsa-studio/actions/runs/37382436307 succeeded for this exact head: build passed with zero errors; 1,902 tests passed, zero skipped, including Administration 71/71. CodeQL analyses passed. Greptile remains pending and CodeRabbit skipped the large diff; both are advisory under the source repository's current reviewer policy. Copilot was requested but has not produced a review.
Historical findings were checked: the publishing guard was fixed by #1117, which is an ancestor of this head; both public jobs require explicit workflow_dispatch and exclude 3.10.x. The environment-loading retry remains the previously accepted #1070 follow-up. The empty Razor branch is intentional and already documented, so the informational static-analysis suggestion requires no code change.
This verdict applies only to the stated commit. Posted by the integrating lead on behalf of the separate reviewing agent; the implementer did not conduct this review.
|
The OIDC subpath finding is fixed in 2cdfcc5. Its inline thread has the regression evidence and fix details. The public publishing observation describes an intentional policy: main produces 3.10.x, whose public publishing is disabled by #1117. This forward merge preserves that workflow byte-for-byte. The separate 3.9 release/tag workflow retains public publishing; https://github.com/elsa-workflows/elsa-studio/actions/runs/37172710555 successfully completed both its nuget.org and npmjs.com publishing jobs. Current-main dispatch is not intended to publish 3.9 packages. The environment-load retry remains the previously accepted #1070 follow-up. Please reassess the new head with these explicit scope and policy dispositions. |
sfmskywalker
left a comment
There was a problem hiding this comment.
Elsa 3 Code Review: APPROVE + HIGH @ 2cdfcc5
Independent review found no actionable defects. OIDC logout preserves root, subpath, and nested hosting paths while retaining POST and antiforgery protection. The helper and component match the existing Core implementation. Rendered regression tests reproduced the failure before the fix and passed afterward.
Exact-head CI https://github.com/elsa-workflows/elsa-studio/actions/runs/37384476983 passed: zero build errors, 1,908 tests passed, zero skipped. All CodeQL checks passed. Greptile reviewed this head at 5/5 with no outstanding findings. The previously reviewed release reconciliation, preserved publishing policy and explicit #1070 follow-up are unchanged.
Posted by the integrating lead on behalf of the separate workroom QA agent. The reviewer made no source edits and did not implement this PR.
Studio main is missing work shipped on the 3.8 and 3.9 release lines. This brings current main (
efde64ef) and release/3.9.0 (a30ed7c9) together while preserving both histories.The change carries permission-aware navigation/actions, dashboard and environment loading fixes, feature catalog matching, execution-details drawer, authentication fixes, and regression tests. Main's 3.10 branding, backend-authoritative Secrets create capability/retry behavior, and current publishing workflow remain intact. The API client dependency advances to the released 3.9.0 contract required by the incoming code.
Secrets tests now model the backend capability correctly, and the picker avoids imposing a second local permission decision over that capability. Hosted OIDC sign-out now preserves root or nested hosting prefixes, using the implementation already present in consolidated Core; rendered form tests reproduce and cover the subpath regression.
Validation:
dea56950ab7e269d13d008fd61b2ebd10454843c: build passed with zero errors; 1,902 tests passed with no failures/skips. https://github.com/elsa-workflows/elsa-studio/actions/runs/373824363072cdfcc525945e99a2ab2c1a02fa3053a0e8dce20: rendered regression reproduced two subpath failures before the fix; build passed and 16 focused sign-out tests passed after it. Refreshed hosted CI and exact-head approval are pending.Merge with a merge commit, preserving source ancestry. After exact-head CI and review pass, use a merge message containing
[skip ci]to suppress this repository's automatic Feedz publisher on main. No package publication, release, deployment, or publisher cutover is included.Refs elsa-workflows/elsa-core#8623, elsa-workflows/elsa-core#8194, elsa-workflows/elsa-core#8624.