From f7fc869e52526372e948018ce176be2a2c702fba Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Thu, 13 Aug 2026 11:37:06 +0200 Subject: [PATCH 1/4] :books: Unify doc added for nitrate apis (#11231) --- backend/src/app/rpc/commands/nitrate.clj | 24 +++++------ backend/src/app/rpc/management/nitrate.clj | 46 +++++++++++----------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/backend/src/app/rpc/commands/nitrate.clj b/backend/src/app/rpc/commands/nitrate.clj index af993ea179..c7ea974a66 100644 --- a/backend/src/app/rpc/commands/nitrate.clj +++ b/backend/src/app/rpc/commands/nitrate.clj @@ -48,7 +48,7 @@ (sv/defmethod ::get-nitrate-connectivity {::rpc/auth true - ::doc/added "2.14" + ::doc/added "2.18" ::sm/params [:map] ::sm/result schema:connectivity} [cfg _params] @@ -64,7 +64,7 @@ (sv/defmethod ::get-subscription-warning {::rpc/auth true - ::doc/added "2.14" + ::doc/added "2.18" ::sm/params [:map] ::sm/result schema:subscription-warning} [cfg {:keys [::rpc/profile-id]}] @@ -80,7 +80,7 @@ (sv/defmethod ::redeem-nitrate-activation-code {::rpc/auth true - ::doc/added "2.14" + ::doc/added "2.18" ::sm/params schema:redeem-activation-code-params ::sm/result schema:redeem-activation-code-result} [cfg {:keys [::rpc/profile-id activation-code]}] @@ -112,7 +112,7 @@ "Returns a Base64-encoded JSON file requesting a Nitrate activation code. Payload includes nitrateId, publicKey, email and iat." {::rpc/auth true - ::doc/added "2.20" + ::doc/added "2.18" ::sm/params [:map] ::sm/result ::sm/text} [cfg {:keys [::rpc/profile-id]}] @@ -360,7 +360,7 @@ (sv/defmethod ::leave-organization {::rpc/auth true - ::doc/added "2.15" + ::doc/added "2.18" ::sm/params schema:leave-organization ::db/transaction true} [cfg {:keys [::rpc/profile-id] :as params}] @@ -404,7 +404,7 @@ [:organization-name ::sm/text]]) (sv/defmethod ::remove-team-from-organization - {::doc/added "2.17" + {::doc/added "2.18" ::sm/params schema:remove-team-from-organization} [cfg {:keys [::rpc/profile-id team-id organization-id organization-name]}] @@ -473,7 +473,7 @@ (sv/defmethod ::add-team-to-organization {::rpc/auth true - ::doc/added "2.17" + ::doc/added "2.18" ::sm/params schema:add-team-to-organization ::db/transaction true} [cfg {:keys [::rpc/profile-id team-id organization-id]}] @@ -558,7 +558,7 @@ (sv/defmethod ::check-organization-members {::rpc/auth true - ::doc/added "2.17" + ::doc/added "2.18" ::sm/params schema:check-organization-members-params ::sm/result [:map-of :string :boolean] ::db/transaction true} @@ -583,7 +583,7 @@ (sv/defmethod ::all-organization-members-in-team {::rpc/auth true - ::doc/added "2.17" + ::doc/added "2.18" ::sm/params schema:all-organization-members-in-team-params ::sm/result ::sm/boolean} [cfg {:keys [::rpc/profile-id team-id organization-id]}] @@ -607,7 +607,7 @@ (sv/defmethod ::all-team-members-in-organizations {::rpc/auth true - ::doc/added "2.17" + ::doc/added "2.18" ::sm/params schema:all-team-members-in-organizations-params ::sm/result [:map-of ::sm/uuid ::sm/boolean]} [cfg {:keys [::rpc/profile-id team-id organization-ids]}] @@ -643,7 +643,7 @@ (sv/defmethod ::check-team-external-invitations {::rpc/auth true - ::doc/added "2.17" + ::doc/added "2.18" ::sm/params schema:check-team-external-invitations-params ::sm/result schema:check-team-external-invitations-result ::db/transaction true} @@ -677,7 +677,7 @@ the client must redirect there. The OIDC provider itself handles re-authentication transparently if the user already has an active SSO session." {::rpc/auth true - ::doc/added "2.19" + ::doc/added "2.18" ::sm/params schema:check-nitrate-sso ::nitrate/sso false} [cfg {:keys [::rpc/profile-id team-id organization-id url] :as params}] diff --git a/backend/src/app/rpc/management/nitrate.clj b/backend/src/app/rpc/management/nitrate.clj index ca334ffb79..d888308dde 100644 --- a/backend/src/app/rpc/management/nitrate.clj +++ b/backend/src/app/rpc/management/nitrate.clj @@ -54,7 +54,7 @@ (sv/defmethod ::authenticate "Authenticate the current user" - {::doc/added "2.14" + {::doc/added "2.18" ::sm/params [:map] ::sm/result schema:profile ::nitrate/sso false} @@ -94,7 +94,7 @@ (sv/defmethod ::get-penpot-version "Get the current Penpot version" - {::doc/added "2.14" + {::doc/added "2.18" ::sm/params [:map] ::sm/result schema:get-penpot-version-result ::rpc/auth false} @@ -106,7 +106,7 @@ (sv/defmethod ::get-teams "List teams for which current user is owner" - {::doc/added "2.14" + {::doc/added "2.18" ::sm/params [:map] ::sm/result schema:get-teams-result ::nitrate/sso false} @@ -130,7 +130,7 @@ "Store an organization logo in penpot storage and return its ID. Accepts an optional previous-id to mark the old logo for garbage collection when replacing an existing one." - {::doc/added "2.17" + {::doc/added "2.18" ::sm/params schema:upload-organization-logo ::sm/result schema:upload-organization-logo-result ::nitrate/sso false} @@ -151,7 +151,7 @@ (sv/defmethod ::notify-team-change "Notify to Penpot a team change from nitrate" - {::doc/added "2.14" + {::doc/added "2.18" ::sm/params cto/schema:team-with-organization ::rpc/auth false} [cfg team] @@ -168,7 +168,7 @@ (sv/defmethod ::notify-user-added-to-organization "Notify to Penpot that an user has joined an organization from nitrate" - {::doc/added "2.14" + {::doc/added "2.18" ::sm/params schema:notify-user-added-to-organization ::rpc/auth false} [cfg {:keys [profile-id organization-id]}] @@ -199,7 +199,7 @@ (sv/defmethod ::get-managed-profiles "List profiles that belong to teams for which current user is owner" - {::doc/added "2.14" + {::doc/added "2.18" ::sm/params [:map] ::sm/result schema:managed-profile-result ::nitrate/sso false} @@ -239,7 +239,7 @@ (sv/defmethod ::get-teams-summary "Get summary information for a list of teams" - {::doc/added "2.15" + {::doc/added "2.18" ::sm/params schema:get-teams-summary-params ::sm/result schema:get-teams-summary-result ::nitrate/sso false} @@ -360,7 +360,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::notify-organization-deletion "For a deleted organization, preserve organization teams and only prefix or delete imported Your Penpot teams before notifying connected users." - {::doc/added "2.15" + {::doc/added "2.18" ::sm/params schema:notify-organization-deletion ::rpc/auth false} [cfg {:keys [organization-id]}] @@ -406,7 +406,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::get-profile-by-email "Get profile by email" - {::doc/added "2.15" + {::doc/added "2.18" ::sm/params [:map [:email ::sm/email]] ::sm/result schema:profile ::nitrate/sso false} @@ -430,7 +430,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::get-profile-by-id "Get profile by email" - {::doc/added "2.15" + {::doc/added "2.18" ::sm/params [:map [:id ::sm/uuid]] ::sm/result schema:profile ::nitrate/sso false} @@ -465,7 +465,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::get-organization-member-team-counts "Get the number of non-default teams each profile belongs to within a set of teams." - {::doc/added "2.15" + {::doc/added "2.18" ::sm/params schema:get-organization-member-team-counts-params ::sm/result schema:get-organization-member-team-counts-result ::rpc/auth false} @@ -505,7 +505,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::invite-to-organization "Invite to organization" - {::doc/added "2.15" + {::doc/added "2.18" ::sm/params [:map [:email ::sm/email] [:organization cto/schema:organization-with-avatar]] @@ -537,7 +537,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::get-organization-invitations "Get valid invitations for an organization, returning at most one invitation per email." - {::doc/added "2.16" + {::doc/added "2.18" ::sm/params schema:get-organization-invitations-params ::sm/result schema:get-organization-invitations-result ::nitrate/sso false} @@ -565,7 +565,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::delete-organization-invitations "Delete all invitations for one email in an organization scope (organization + organization teams)." - {::doc/added "2.16" + {::doc/added "2.18" ::sm/params schema:delete-organization-invitations-params ::nitrate/sso false} [cfg {:keys [organization-id email]}] @@ -630,7 +630,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::remove-from-organization "Remove an user from an organization" - {::doc/added "2.17" + {::doc/added "2.18" ::sm/params [:map [:profile-id ::sm/uuid] [:organization-id ::sm/uuid] @@ -675,7 +675,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::get-remove-from-organization-summary "Get a summary of the teams that would be deleted, transferred, or exited if the user were removed from the organization" - {::doc/added "2.17" + {::doc/added "2.18" ::sm/params [:map [:profile-id ::sm/uuid] [:organization-id ::sm/uuid] @@ -710,7 +710,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::send-renewal-email "Send an Enterprise subscription renewal notice email to a user." - {::doc/added "2.17" + {::doc/added "2.18" ::sm/params schema:send-renewal-email-params ::rpc/auth false} [cfg {:keys [profile-id user-email user-name renewal-date estimated-amount organizations]}] @@ -823,7 +823,7 @@ RETURNING id, deleted_at;") "Push audit events from nitrate (strictly for nitrate backend events)" - {::doc/added "2.19" + {::doc/added "2.18" ::audit/skip true ::sm/params schema:push-audit-events-params ::rpc/auth false} @@ -930,7 +930,7 @@ RETURNING id, deleted_at;") (sv/defmethod ::get-teams-detail "Get detailed information for all non-deleted teams in an organization, including owner info and project/file/member counts." - {::doc/added "2.20" + {::doc/added "2.18" ::sm/params schema:get-teams-detail-params ::sm/result schema:get-teams-detail-result ::nitrate/sso false} @@ -958,7 +958,7 @@ RETURNING id, deleted_at;") "Validate an organization SSO configuration by generating a login redirect URL. Nitrate calls this while configuring SSO to verify client credentials and OIDC discovery before saving the settings." - {::doc/added "2.20" + {::doc/added "2.18" ::sm/params cto/schema:nitrate-sso ::sm/result schema:check-organization-sso-result ::rpc/auth false} @@ -968,7 +968,7 @@ RETURNING id, deleted_at;") ;; ---- API: notify-organization-sso-change (sv/defmethod ::notify-organization-sso-change "Nitrate notifies that an organization sso values have changed" - {::doc/added "2.19" + {::doc/added "2.18" ::sm/params [:map [:organization-id ::sm/uuid] [:updated-props ::sm/boolean] @@ -1017,7 +1017,7 @@ RETURNING id, deleted_at;") bulk-creation screen; access is gated by the shared key and, in Nitrate, an email allow-list. Requires the `admin-console-bulk-create-profiles` flag, disabled by default so it is only available on test environments." - {::doc/added "2.19" + {::doc/added "2.18" ::sm/params schema:bulk-create-profiles-params ::sm/result schema:bulk-create-profiles-result ::rpc/auth false} From 9528400c6e86ea9f3c88e8de5483a828ba45aa6b Mon Sep 17 00:00:00 2001 From: Yamila Moreno Date: Thu, 13 Aug 2026 12:03:27 +0200 Subject: [PATCH 2/4] :bug: Forward internal Host in nginx proxy_pass to backend/exporter (#11233) The global `proxy_set_header Host $http_host;` forwarded the client-facing Host to internal proxy_pass calls (backend/exporter), breaking mTLS routing in service-mesh setups (e.g. Istio STRICT mode), which match outbound requests to a cluster based on Host/:authority. Explicitly set `Host $proxy_host` on /api, /assets, /api/export, /readyz and /ws/notifications so these calls always target the correct internal service host, independent of the client's original Host header. Fixes #10835 Signed-off-by: Sebastien MALOT Co-authored-by: Sebastien MALOT --- docker/images/files/nginx.conf.template | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker/images/files/nginx.conf.template b/docker/images/files/nginx.conf.template index 3e91a91714..5ca929c124 100644 --- a/docker/images/files/nginx.conf.template +++ b/docker/images/files/nginx.conf.template @@ -111,6 +111,7 @@ http { } location /assets { + proxy_set_header Host $proxy_host; proxy_pass $PENPOT_BACKEND_URI/assets; recursive_error_pages on; proxy_intercept_errors on; @@ -127,10 +128,12 @@ http { } location /api/export { + proxy_set_header Host $proxy_host; proxy_pass $PENPOT_EXPORTER_URI; } location /api { + proxy_set_header Host $proxy_host; proxy_pass $PENPOT_BACKEND_URI/api; proxy_buffering off; } @@ -142,10 +145,12 @@ http { location /readyz { access_log off; + proxy_set_header Host $proxy_host; proxy_pass $PENPOT_BACKEND_URI$request_uri; } location /ws/notifications { + proxy_set_header Host $proxy_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_pass $PENPOT_BACKEND_URI/ws/notifications; From 3db7548c19e1e9d9b26b0401c5c65db91d895fce Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Thu, 13 Aug 2026 13:06:26 +0200 Subject: [PATCH 3/4] :lipstick: Change nitrate error message (#11232) --- frontend/src/app/main/ui/settings/subscription.cljs | 2 +- frontend/translations/en.po | 6 ------ frontend/translations/es.po | 7 ------- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/frontend/src/app/main/ui/settings/subscription.cljs b/frontend/src/app/main/ui/settings/subscription.cljs index 98626cda7d..a8a7f3fed9 100644 --- a/frontend/src/app/main/ui/settings/subscription.cljs +++ b/frontend/src/app/main/ui/settings/subscription.cljs @@ -425,7 +425,7 @@ nitrate-toast-message (condp = params-subscription - dnt/nitrate-checkout-finish-error-token (tr "subscription.error.nitrate.checkout-finish-failed") + dnt/nitrate-checkout-finish-error-token (tr "subscription.error.nitrate.checkout-failed") dnt/nitrate-checkout-cancelled-token (tr "subscription.error.nitrate.checkout-cancelled") nil) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index e5e8967f42..f3f01fcecf 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -6073,12 +6073,6 @@ msgstr "" "The payment was not completed. Please try again. " "If the problem persists, contact us: support@penpot.app." -#: src/app/main/ui/settings/subscription.cljs:407 -msgid "subscription.error.nitrate.checkout-finish-failed" -msgstr "" -"We couldn’t confirm your subscription. Please check your subscription " -"status on the Subscription page. You may try again if needed." - #: src/app/main/ui/settings/sidebar.cljs:114, src/app/main/ui/settings/subscription.cljs:505, src/app/main/ui/settings/subscription.cljs:565 msgid "subscription.labels" msgstr "Subscription" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 84790f1d86..1b1c8b4c24 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5937,13 +5937,6 @@ msgstr "" "No hemos podido iniciar el proceso de pago. Inténtalo de nuevo. Si el " "problema persiste, contáctanos: support@penpot.app." -#: src/app/main/ui/settings/subscription.cljs:407 -msgid "subscription.error.nitrate.checkout-finish-failed" -msgstr "" -"No hemos podido confirmar tu suscripción. Revisa el estado de tu " -"suscripción en la página de Suscripciones. Puedes volver a intentarlo si lo " -"necesitas." - #: src/app/main/ui/settings/sidebar.cljs:114, src/app/main/ui/settings/subscription.cljs:505, src/app/main/ui/settings/subscription.cljs:565 msgid "subscription.labels" msgstr "Suscripción" From c7f036bed00eae8aa43d2154ef55557e7990f874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Valderrama?= Date: Thu, 13 Aug 2026 13:15:59 +0200 Subject: [PATCH 4/4] :bug: Fix organization invitation schema validation for logo URI (#11238) --- backend/src/app/rpc/management/nitrate.clj | 3 ++- backend/test/backend_tests/rpc_management_nitrate_test.clj | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/app/rpc/management/nitrate.clj b/backend/src/app/rpc/management/nitrate.clj index d888308dde..8f07c90612 100644 --- a/backend/src/app/rpc/management/nitrate.clj +++ b/backend/src/app/rpc/management/nitrate.clj @@ -17,6 +17,7 @@ [app.common.types.organization :as cto] [app.common.types.profile :refer [schema:profile, schema:basic-profile]] [app.common.types.team :refer [schema:team]] + [app.common.uri :as u] [app.common.uuid :as uuid] [app.config :as cf] [app.db :as db] @@ -499,7 +500,7 @@ RETURNING id, deleted_at;") {:id id :name name :initials (if logo-id "" (d/get-initials name)) - :logo (when logo-id (files/resolve-public-uri logo-id)) + :logo (when logo-id (u/uri (files/resolve-public-uri logo-id))) :avatar-bg-url (when-not logo-id avatar-bg-url) :sso-active (true? sso-active)})) diff --git a/backend/test/backend_tests/rpc_management_nitrate_test.clj b/backend/test/backend_tests/rpc_management_nitrate_test.clj index 4cb32401cf..455f875fd3 100644 --- a/backend/test/backend_tests/rpc_management_nitrate_test.clj +++ b/backend/test/backend_tests/rpc_management_nitrate_test.clj @@ -178,7 +178,7 @@ (t/is (th/success? out)) (t/is (= "Trusted Organization" (:name organization))) (t/is (= "" (:initials organization))) - (t/is (str/ends-with? (:logo organization) + (t/is (str/ends-with? (str (:logo organization)) (str "/assets/by-id/" logo-id))) (t/is (nil? (:avatar-bg-url organization))) (t/is (true? (:sso-active organization))))))))