From 8bfcd40bd28f6e9f064334b2bbc8ee6a753a8d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 15 Aug 2026 03:09:50 +0000 Subject: [PATCH] music's library browser depends on another plugin's permission, not just its own MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MusicBrowser lists folders with GET /file-browser/ls rather than through the music sidecar. /file-browser belongs to `files`, which is `confined` — so a member granted `music` and not `files` gets a working player, working favourites and an empty library, and `files` is not a grant that can simply be handed over, since authorize.ts drops a confined grant for an account with no Linux user. First cross-plugin PERMISSION dependency in the system, and a different animal from offscale's. That one is ConsoleView → TerminalView: code, resolved at build time, worst case a plugin that will not compile. This resolves at request time, per account, and fails as a screen that renders perfectly and shows nothing. Three shapes written down, none chosen. Moving the listing into the sidecar is probably right — it is the same rule offscale follows, that the sidecar absorbs everything — but it is tomorrow's call. Recorded now rather than trusted to memory: it was found by reading, after the extraction was already verified and pushed, so nothing was going to surface it again on its own. --- plugins/music/PLUGIN.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/plugins/music/PLUGIN.md b/plugins/music/PLUGIN.md index 6f3b020a..57326994 100644 --- a/plugins/music/PLUGIN.md +++ b/plugins/music/PLUGIN.md @@ -205,6 +205,37 @@ exist before. ## Still open +### The library browser reads the filesystem, not this plugin — and that is a PERMISSION dependency + +Found 2026-08-15, after the extraction landed, by reading the code rather than by anything failing. + +`MusicBrowser.tsx` lists folders with `GET /file-browser/ls`, not through the music sidecar +(`MusicBrowser.tsx:63,81`). `/file-browser` belongs to the **`files`** capability, and `files` is +**`confined`** — so: + +- a member granted `music` but not `files` gets a working player, working favourites, and an **empty + library**, because every listing 403s; +- and `files` is not a grant that can simply be handed over. `authorize.ts` drops a confined grant for an + account with no `osUser`, so it means nothing without a per-user Linux account. + +This is the first **cross-plugin permission dependency** in the system, and it is a different animal from +the one offscale has. Offscale's `ConsoleView` → `TerminalView` is a CODE dependency: it resolves at build +time, and the worst case is a plugin that will not compile. This one resolves at request time, per +account, and its failure mode is a screen that renders perfectly and shows nothing. + +Three possible shapes, none chosen: + +1. **The sidecar lists.** Music already walks the library for its index — `GET /music/ls` would put the + listing behind the `music` permission where it belongs, and the plugin stops needing `files` at all. + Most self-contained, and the most work. +2. **The manifest declares a permission dependency**, and the platform refuses the grant or warns. Honest, + but it makes one plugin's grant conditional on another capability, which is new machinery. +3. **Leave it and document it** — a member needs `files` too. Cheapest, and it quietly ties a music grant + to a Linux account, which is a much bigger commitment than the owner is agreeing to on that page. + +(1) is probably right, and it is the same shape as offscale's rule that the sidecar absorbs everything. +Not tonight's call. + - **`hasPersonalWrites` reads `c.personal` only**, so the permissions API reports `false` for a plugin that declares the same thing through `readOnlyWrites`. Nothing renders the field, so it is dead on the wire — noted rather than fixed.