feat(plugins): allow mounting library directories as read-write (#5122)

* feat(plugins): mount library directories as read-only by default

Add an AllowWriteAccess boolean to the plugin model, defaulting to
false. When off, library directories are mounted with the extism "ro:"
prefix (read-only). Admins can explicitly grant write access via a new
toggle in the Library Permission card.

* test: add tests to buildAllowedPaths

Signed-off-by: Deluan <deluan@navidrome.org>

* chore: improve allowed paths logging for library access

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan Quintão
2026-02-28 10:59:13 -05:00
committed by GitHub
parent d134de1061
commit d9a215e1e3
13 changed files with 229 additions and 75 deletions
+12 -10
View File
@@ -18,7 +18,7 @@ type MockPluginManager struct {
// UpdatePluginUsersFn is called when UpdatePluginUsers is invoked. If nil, returns UsersError.
UpdatePluginUsersFn func(ctx context.Context, id, usersJSON string, allUsers bool) error
// UpdatePluginLibrariesFn is called when UpdatePluginLibraries is invoked. If nil, returns LibrariesError.
UpdatePluginLibrariesFn func(ctx context.Context, id, librariesJSON string, allLibraries bool) error
UpdatePluginLibrariesFn func(ctx context.Context, id, librariesJSON string, allLibraries, allowWriteAccess bool) error
// RescanPluginsFn is called when RescanPlugins is invoked. If nil, returns RescanError.
RescanPluginsFn func(ctx context.Context) error
@@ -48,9 +48,10 @@ type MockPluginManager struct {
AllUsers bool
}
UpdatePluginLibrariesCalls []struct {
ID string
LibrariesJSON string
AllLibraries bool
ID string
LibrariesJSON string
AllLibraries bool
AllowWriteAccess bool
}
RescanPluginsCalls int
}
@@ -105,14 +106,15 @@ func (m *MockPluginManager) UpdatePluginUsers(ctx context.Context, id, usersJSON
return m.UsersError
}
func (m *MockPluginManager) UpdatePluginLibraries(ctx context.Context, id, librariesJSON string, allLibraries bool) error {
func (m *MockPluginManager) UpdatePluginLibraries(ctx context.Context, id, librariesJSON string, allLibraries, allowWriteAccess bool) error {
m.UpdatePluginLibrariesCalls = append(m.UpdatePluginLibrariesCalls, struct {
ID string
LibrariesJSON string
AllLibraries bool
}{ID: id, LibrariesJSON: librariesJSON, AllLibraries: allLibraries})
ID string
LibrariesJSON string
AllLibraries bool
AllowWriteAccess bool
}{ID: id, LibrariesJSON: librariesJSON, AllLibraries: allLibraries, AllowWriteAccess: allowWriteAccess})
if m.UpdatePluginLibrariesFn != nil {
return m.UpdatePluginLibrariesFn(ctx, id, librariesJSON, allLibraries)
return m.UpdatePluginLibrariesFn(ctx, id, librariesJSON, allLibraries, allowWriteAccess)
}
return m.LibrariesError
}