Foss main next#26
Draft
hunzlahmalik wants to merge 24 commits into
Draft
Conversation
✨ Add ForwardAuth transparent SSO authentication support
The logout event was redirecting to MPASS_SIGNOUT_URL, which pointed at
oauth2-proxy's /sign_out with an rd= that depended on Cognito hosted
/logout being available. In this deployment the app client has no
hosted /logout endpoint, so the Cognito session always survives logout
and the extra redirect layer was dead weight. The URL was injected at
container start via nginx-entrypoint.sh and read from a browser global
(penpotMpassSignoutUrl), coupling the frontend bundle to identity-
provider config baked in by an external script.
Simplified to derive the portal host from the current URL:
- Rewrite "foss-<app>.<domain>" -> "foss.<domain>" and redirect there
after the native :logout cmd clears the Penpot session.
- The portal host is outside ForwardAuth, so the user lands on the
landing page instead of being silently re-authed into the
dashboard. Re-auth still happens the next time the user clicks
into a gated app, which is the expected behavior while Cognito
hosted /logout is absent.
The cf/mpass-signout-url var remains defined in config.cljs for
backwards compatibility with the nginx injection script but is no
longer consumed by the logout flow.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Usama Sadiq <usama7274@gmail.com>
fix(auth): land on portal after logout, drop unreachable Cognito hop
- Configure default auth-token cookie max-age and renewal in config - Add backend tests for env override and renew-session? behavior Signed-off-by: jawad-khan <jawadkhan444@gmail.com> Made-with: Cursor
✨ Add session cookie defaults and backend tests
✨ Make askii.ai the default email domain
use moneta instead of foss in logout
Replace hardcoded "moneta." prefix with an empty string so the regex strips just the leading subdomain (e.g. app.moneta.askii.ai → moneta.askii.ai) regardless of the deployment domain. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch to /^[^.]+\.(?=[^.]*\.[^.]*\.)/ so the subdomain is only stripped when at least two dot-separated parts remain, preventing over-stripping on bare domains. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…omain fix: strip first subdomain for portal redirect on signout
In x-auth-request-headers (oauth2-proxy / Cognito SSO) mode the email
is the user's identity as injected by the upstream IdP via the
X-Auth-Request-Email header on every request. Letting a user change
their Penpot email locally would diverge it from the IdP-supplied
email, and the next request would either fail to authenticate (the
auth_request middleware looks profiles up by email) or auto-create
a fresh duplicate profile under the original IdP email — losing the
user's workspace either way.
Backend
- rpc/commands/profile.clj :: request-email-change refuses with
:email-managed-by-external-idp when the :x-auth-request-headers
flag is enabled, before any token is generated or any database
write happens.
- rpc/commands/verify_token.clj :: process-token :change-email
refuses under the same condition. Belt-and-suspenders for tokens
that may already exist (e.g., generated before SSO mode was
turned on) or for any code path that bypasses the issue-side RPC.
Frontend
- settings/profile.cljs renders the email row in two branches: in
SSO mode (cf/mpass-signout-url is set) the row is read-only with
no click handler and no "Change email" link; otherwise the
upstream behaviour is preserved unchanged. Pure UX guard — the
backend rejects the change regardless, so this just avoids
confusing the user with an action that would fail at the API
layer.
cf/mpass-signout-url is the SSO-mode signal injected at runtime by
docker/images/files/nginx-entrypoint.sh from the MPASS_SIGNOUT_URL
env var (the existing 3-layer logout URL configured in the devstack).
Tested manually: with :x-auth-request-headers enabled,
/#/settings/profile loads cleanly, the email field is disabled, and
the "Change email" link is not rendered.
Addresses Copilot review feedback on the email-change SSO block.
1. Frontend gated on cf/mpass-signout-url (runtime config injection
from MPASS_SIGNOUT_URL env), backend gated on :x-auth-request-headers
(parsed from PENPOT_FLAGS env). The two envs are independently
settable, so a partial-config deploy could enable the backend gate
while leaving the UI showing a button that only fails. Switch the
frontend signal to (contains? cf/flags :x-auth-request-headers) —
same source as the backend, so UI and RPC stay aligned regardless of
how MPASS_SIGNOUT_URL is wired.
2. Add backend regression tests covering both gates:
- email-change-request-blocked-when-x-auth-request-headers-enabled
asserts request-email-change returns
{:type :restriction :code :email-managed-by-external-idp} and
never falls through to change-email-immediately!.
- email-change-token-blocked-when-x-auth-request-headers-enabled
mints a valid :change-email token, then with the flag set runs
verify-token and asserts the same restriction — the
belt-and-suspenders gate against pre-existing tokens.
Both tests verify the profile email row remains untouched after the
RPC rejection so a future regression that gates only one path or
performs a partial DB write is caught.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the (when (contains? cf/flags :x-auth-request-headers) ...) gate with an unconditional refusal. This Penpot fork is SSO-only — there is no scenario where the email-change flow should succeed: - The auth_request middleware resolves users by email, so a local change diverges the profile from the IdP-asserted X-Auth-Request-Email and either locks the user out or pre-stages a takeover for the next victim's first sign-in. - All other authentication paths are disabled in this fork. Conditional gating left dead branches (change-email-immediately!, request-email-change!, the SMTP-fallback fork) sitting one flag-flip away from re-introducing the takeover. Removing them shrinks the attack surface to a single ex/raise. Backend - profile.clj: defmethod ::request-email-change reduced to ex/raise. Removed change-email-immediately! and request-email-change! private fns + their forward declares (now unreachable). - verify_token.clj: defmethod process-token :change-email reduced to ex/raise. Removed the let body that performed the actual update. Frontend - profile.cljs: removed the if/else branch that toggled the change-email link based on cf/flags. Email row is always read-only. Drops the unreachable on-show-change-email handler. Tests - Replaced email-change-request, email-change-request-without-smtp, and the two newly-added flag-conditional tests with two unconditional tests: email-change-request-is-disabled and email-change-token-is-rejected. Both assert the rejection AND that the profile row is not mutated, catching a future regression that performs a partial DB write. Net: -245 / +64 lines. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix(sso): block email changes when x-auth-request-headers is enabled
* feat: Add user in default workspace on login * fix: fixed workspace issue * ✨ Auto join SSO users to provisioned * fix: update backend/src/app/http/auth_request.clj Signed-off-by: Usama Sadiq <usama7274@gmail.com> --------- Co-authored-by: Usama Sadiq <usama.sadiq@arbisoft.com>
…n-minimal 🐛 Re-key session when X-Auth-Request identity differs
# Conflicts: # backend/test/backend_tests/rpc_profile_test.clj
Closed
On macOS Docker Desktop, Node's fs.cpSync writes files in the bind mount with a com.docker.grpcfuse.ownership xattr declaring mode 200 even when the host inode is 644. The subsequent `cp -a` (and the original `rsync -avr`) then chmod the destination to 200, which lands on the real host inode and renders the bundle unreadable to anything outside the build container (Linux containers via gRPC-FUSE included). chmod-ing packages/server/dist before the copy rewrites the xattr to 644 while the host mode is still 644, so cp -a propagates the correct mode and the bundle is readable downstream. Behaviour on Linux hosts is unchanged: gRPC-FUSE only runs on macOS Docker Desktop; chmod -R is a no-op when modes are already correct. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…attr fix(mcp-build): normalize dist modes before cp -a (macOS gRPC-FUSE)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
for diff comparison purposes only – do not merge