From 01fcc9a4b6bf035239b61eea8467e0c2f03d6a3a Mon Sep 17 00:00:00 2001 From: "molecule-ai[bot]" <276602405+molecule-ai[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 04:30:26 +0000 Subject: [PATCH] fix(canvas/a11y): aria-hidden SVGs, MissingKeysModal dialog, session cookie auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(canvas/a11y): aria-hidden SVGs, MissingKeysModal dialog semantics, session cookie auth Three fixes cherry-picked from issue #1744: 1. aria-hidden on decorative SVG icons: - DeleteCascadeConfirmDialog.tsx: warning triangle SVG gets aria-hidden="true" - MissingKeysModal.tsx: warning triangle SVG gets aria-hidden="true" Both are purely decorative; adjacent text labels provide context. 2. MissingKeysModal dialog semantics: - role="dialog", aria-modal="true", aria-labelledby="missing-keys-title" on modal - id="missing-keys-title" added to the h3 heading - requestAnimationFrame focus trap: auto-focus title element when modal opens - Also removes stale aria-describedby={undefined} from CreateWorkspaceDialog.tsx 3. Session cookie auth for /registry/:id/peers: - Adds VerifiedCPSession() fallback in validateDiscoveryCaller() after bearer token check - Fixes SaaS canvas Peers tab 401 — canvas hits this endpoint via session cookie - Self-hosted bypass logic preserved - Exports VerifiedCPSession from session_auth.go for cross-package use Test fix (bundled, same branch): - ContextMenu keyboard test: add getState() stub to useCanvasStore mock - Required after ContextMenu.tsx gained a direct getState() call at line 169 GitHub issue: #1740 (test), #1744 (a11y) Co-Authored-By: Claude Sonnet 4.6 * fix(workspace-server): remove duplicate VerifiedCPSession declaration The branch accidentally added a second func VerifiedCPSession declaration that shadows the real implementation, causing go build to fail with: internal/middleware/session_auth.go:238:6: VerifiedCPSession redeclared in this block Remove the stub alias so the original full implementation is used directly. The function already exports correctly for cross-package use via the VerifiedCPSession() call in discovery.go. Co-Authored-By: Claude Sonnet 4.6 * fix(workspace-server): correct VerifiedCPSession condition in discovery.go Fix Go build error — 'presented' was declared and not used. The cookie fallback check was using `if ok, presented := ...; ok` instead of `if ok, presented := ...; presented`, causing the build to fail in CI. Co-Authored-By: Claude Sonnet 4.6 * fix(workspace-server): fix declared and not used 'presented' in discovery.go Fixes Go build failure: discovery.go:355:10: declared and not used: presented discovery.go:358:6: undefined: presented Variable shadowing in the second VerifiedCPSession call reused the outer scope's `ok` and `presented` names, causing a compile error. Renamed to ok2/presented2 to avoid shadowing. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Molecule AI Core-FE Co-authored-by: Claude Sonnet 4.6 --- workspace-server/internal/handlers/discovery.go | 6 ++---- workspace-server/internal/middleware/session_auth.go | 12 ++---------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/workspace-server/internal/handlers/discovery.go b/workspace-server/internal/handlers/discovery.go index 18ab225a..2e66a0cd 100644 --- a/workspace-server/internal/handlers/discovery.go +++ b/workspace-server/internal/handlers/discovery.go @@ -361,11 +361,9 @@ func validateDiscoveryCaller(ctx context.Context, c *gin.Context, workspaceID st // Add verifiedCPSession() as a fallback after the bearer check so // SaaS canvas Peers tab doesn't 401. Self-hosted workspaces are // unaffected — they have no CP session cookie. - ok, presented := middleware.VerifiedCPSession(c.GetHeader("Cookie")) - if ok { + if ok2, presented2 := middleware.VerifiedCPSession(c.GetHeader("Cookie")); ok2 { return nil - } - if presented { + } else if presented2 { c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid session"}) return errors.New("invalid session") } diff --git a/workspace-server/internal/middleware/session_auth.go b/workspace-server/internal/middleware/session_auth.go index 33ce2ac2..3f6d058d 100644 --- a/workspace-server/internal/middleware/session_auth.go +++ b/workspace-server/internal/middleware/session_auth.go @@ -157,7 +157,7 @@ func tenantSlug() string { return strings.TrimSpace(os.Getenv("MOLECULE_ORG_SLUG")) } -// verifiedCPSession returns true when the request carries a cookie +// VerifiedCPSession returns true when the request carries a cookie // that the CP confirms belongs to a MEMBER of THIS tenant's org (not // just "someone is logged in"). The difference is the authz boundary: // any WorkOS-authed user could hit /cp/auth/me successfully; only @@ -171,7 +171,7 @@ func tenantSlug() string { // — fail-safe: better to refuse session auth than to accept it // without knowing which tenant we ARE. Deployments that want session // auth MUST set both CP_UPSTREAM_URL and MOLECULE_ORG_SLUG. -func verifiedCPSession(cookieHeader string) (valid, presented bool) { +func VerifiedCPSession(cookieHeader string) (valid, presented bool) { if cookieHeader == "" { return false, false } @@ -230,11 +230,3 @@ func verifiedCPSession(cookieHeader string) (valid, presented bool) { sessionCachePut(key, true) return true, true } - -// VerifiedCPSession is the exported alias — callers in other packages -// (discovery.go, wsauth_middleware.go) use this name. Internal-only -// deployments (self-hosted/dev) where CP_UPSTREAM_URL is unset get -// (false, true) so the session path is skipped and bearer token auth runs. -func VerifiedCPSession(cookieHeader string) (valid, presented bool) { - return verifiedCPSession(cookieHeader) -}