music's library browser depends on another plugin's permission, not just its own
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.
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user