🐛 Fix plugin library.connectLibrary breaking Promise contract on permission failure (#9158)

`library.connectLibrary()` declared its permission check **outside** the
`js/Promise.` wrapper, so when a plugin without `library:write` permission
called `await library.connectLibrary(id)` the method did not return a
`Promise` at all:

- With the default `throwValidationErrors` flag off → `u/not-valid`
  logs to console and returns `nil`. `await nil` resolves to `nil`, so
  the plugin sees a "successful" result and crashes later when it tries
  to use methods on what it thinks is a `LibraryProxy`.
- With `throwValidationErrors` on → `u/not-valid` throws synchronously,
  so the caller gets a thrown exception instead of a rejected promise —
  inconsistent with every other `library:*` / `content:*` method which
  always returns a Promise that rejects via `reject-not-valid`.

Additionally, the in-Promise `(not (string? library-id))` branch used
`(reject nil)` — the plugin got a rejected Promise but with no error
message.

Move the permission check inside the Promise constructor and replace
both validation errors with `u/reject-not-valid`, matching the pattern
used by the sibling methods `restore`, `remove`, `pin`, `saveVersion`,
`findVersions` in `frontend/src/app/plugins/file.cljs` and every other
promise-returning plugin method. No new imports.

Also add a CHANGES.md entry under the 2.17.0 Unreleased bugs-fixed section.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
boskodev790 2026-04-27 10:59:09 -05:00 committed by GitHub
parent f4cf667d2f
commit ea265da1f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 18 deletions

View File

@ -49,6 +49,7 @@
### :bug: Bugs fixed
- Fix plugin API `fileVersion.restore()` promise hanging indefinitely on restore failure [Github #9092](https://github.com/penpot/penpot/issues/9092)
- Fix plugin API `library.connectLibrary()` returning a non-Promise (or throwing synchronously) when the plugin lacks `library:write` permission — the method now always returns a `Promise` and rejects with a structured error message, matching the contract used by every other Promise-returning plugin method (`restore`, `remove`, `pin`, `saveVersion`, `findVersions`, …)
- Fix LDAP provider params schema typo (`bind-passwor``bind-password`) introduced during the `clojure.spec``malli` migration; the schema slot now matches the runtime key actually read by `prepare-params` (`:password (:bind-password cfg)`) and `try-connectivity` (`(:bind-password cfg)`), so a wrong type for the password no longer slips through unvalidated
- Fix `login-with-ldap` silently dropping its error message on the `ldap-not-initialized` restriction (typo `:hide``:hint`); the message `"ldap auth provider is not initialized"` now actually surfaces in logs and error responses instead of being discarded into an unread key
- Fix `PENPOT_OIDC_USER_INFO_SOURCE` flag being silently ignored (`userinfo` / `token`) in the OIDC callback, causing "incomplete user info" failures during registration [Github #9108](https://github.com/penpot/penpot/issues/9108)

View File

@ -1108,23 +1108,20 @@
:connectLibrary
(fn [library-id]
(cond
(not (r/check-permission plugin-id "library:write"))
(u/not-valid plugin-id :connectLibrary "Plugin doesn't have 'library:write' permission")
(js/Promise.
(fn [resolve reject]
(cond
(not (r/check-permission plugin-id "library:write"))
(u/reject-not-valid reject :connectLibrary "Plugin doesn't have 'library:write' permission")
:else
(js/Promise.
(fn [resolve reject]
(cond
(not (string? library-id))
(do (u/not-valid plugin-id :connectLibrary library-id)
(reject nil))
(not (string? library-id))
(u/reject-not-valid reject :connectLibrary library-id)
:else
(let [file-id (:current-file-id @st/state)
library-id (uuid/parse library-id)]
(->> st/stream
(rx/filter (ptk/type? ::dwl/attach-library-finished))
(rx/take 1)
(rx/subs! #(resolve (library-proxy plugin-id library-id)) reject))
(st/emit! (dwl/link-file-to-library file-id library-id))))))))))
:else
(let [file-id (:current-file-id @st/state)
library-id (uuid/parse library-id)]
(->> st/stream
(rx/filter (ptk/type? ::dwl/attach-library-finished))
(rx/take 1)
(rx/subs! #(resolve (library-proxy plugin-id library-id)) reject))
(st/emit! (dwl/link-file-to-library file-id library-id)))))))))