Plugins: StaticFS should implement FSRemover (#110706) (#110945)

* Plugins: StaticFS should implement FSRemover (#110706)

make staticfs implement fs removal interface

* fix test

* fix build

* undo test remove
This commit is contained in:
Will Browne
2025-09-11 14:44:34 +01:00
committed by GitHub
parent 323a4a24fa
commit 394f5d8ce4
8 changed files with 379 additions and 6 deletions
+9
View File
@@ -236,6 +236,15 @@ func (f StaticFS) Files() ([]string, error) {
return files, nil
}
func (f StaticFS) Remove() error {
if remover, ok := f.FS.(FSRemover); ok {
if err := remover.Remove(); err != nil {
return err
}
}
return nil
}
// LocalFile implements a fs.File for accessing the local filesystem.
type LocalFile struct {
f *os.File
+16 -1
View File
@@ -270,12 +270,27 @@ func TestStaticFS(t *testing.T) {
require.Equal(t, []string{allowedFn, deniedFn}, files)
})
t.Run("staticfs filters underelying fs's files", func(t *testing.T) {
t.Run("staticfs filters underlying fs's files", func(t *testing.T) {
files, err := staticFS.Files()
require.NoError(t, err)
require.Equal(t, []string{allowedFn}, files)
})
})
t.Run("FSRemover interface implementation verification", func(t *testing.T) {
tmpDir := t.TempDir()
lfs := NewLocalFS(tmpDir)
var localFSInterface FS = lfs
_, isRemover := localFSInterface.(FSRemover)
require.True(t, isRemover)
sfs, err := NewStaticFS(localFS)
require.NoError(t, err)
var staticFSInterface FS = sfs
_, isRemover = staticFSInterface.(FSRemover)
require.True(t, isRemover)
})
}
// TestFSTwoDotsInFileName ensures that LocalFS and StaticFS allow two dots in file names.
+99
View File
@@ -5,6 +5,8 @@ import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"testing"
@@ -416,3 +418,100 @@ func createPlugin(t *testing.T, pluginID string, class plugins.Class, managed, b
func testCompatOpts() plugins.AddOpts {
return plugins.NewAddOpts("10.0.0", runtime.GOOS, runtime.GOARCH, "")
}
func TestPluginInstaller_Removal(t *testing.T) {
tmpDir := t.TempDir()
t.Run("LocalFS plugin removal succeeds via installer.Remove", func(t *testing.T) {
pluginDir := filepath.Join(tmpDir, "localfs-plugin")
err := os.MkdirAll(pluginDir, 0750)
require.NoError(t, err)
pluginJSON := `{
"id": "localfs-plugin",
"name": "LocalFS Plugin",
"type": "datasource",
"info": {
"version": "1.0.0"
}
}`
err = os.WriteFile(filepath.Join(pluginDir, "plugin.json"), []byte(pluginJSON), 0644)
require.NoError(t, err)
localFS := plugins.NewLocalFS(pluginDir)
pluginV1 := createPlugin(t, "localfs-plugin", plugins.ClassExternal, true, true, func(plugin *plugins.Plugin) {
plugin.Info.Version = "1.0.0"
plugin.FS = localFS
})
registry := &fakes.FakePluginRegistry{
Store: map[string]*plugins.Plugin{
"localfs-plugin": pluginV1,
},
}
loader := &fakes.FakeLoader{
UnloadFunc: func(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
return p, nil
},
}
_, err = os.Stat(pluginDir)
require.NoError(t, err)
inst := New(registry, loader, &fakes.FakePluginRepo{}, &fakes.FakePluginStorage{}, storage.SimpleDirNameGeneratorFunc, &fakes.FakeAuthService{})
err = inst.Remove(context.Background(), "localfs-plugin", "1.0.0")
require.NoError(t, err)
_, err = os.Stat(pluginDir)
require.True(t, os.IsNotExist(err))
})
t.Run("StaticFS plugin removal is skipped via installer.Remove", func(t *testing.T) {
pluginDir := filepath.Join(tmpDir, "staticfs-plugin")
err := os.MkdirAll(pluginDir, 0750)
require.NoError(t, err)
pluginJSON := `{
"id": "staticfs-plugin",
"name": "StaticFS Plugin",
"type": "datasource",
"info": {
"version": "1.0.0"
}
}`
err = os.WriteFile(filepath.Join(pluginDir, "plugin.json"), []byte(pluginJSON), 0644)
require.NoError(t, err)
localFS := plugins.NewLocalFS(pluginDir)
staticFS, err := plugins.NewStaticFS(localFS)
require.NoError(t, err)
pluginV1 := createPlugin(t, "staticfs-plugin", plugins.ClassExternal, true, true, func(plugin *plugins.Plugin) {
plugin.Info.Version = "1.0.0"
plugin.FS = staticFS
})
registry := &fakes.FakePluginRegistry{
Store: map[string]*plugins.Plugin{
"staticfs-plugin": pluginV1,
},
}
loader := &fakes.FakeLoader{
UnloadFunc: func(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
return p, nil
},
}
_, err = os.Stat(pluginDir)
require.NoError(t, err)
inst := New(registry, loader, &fakes.FakePluginRepo{}, &fakes.FakePluginStorage{}, storage.SimpleDirNameGeneratorFunc, &fakes.FakeAuthService{})
err = inst.Remove(context.Background(), "staticfs-plugin", "1.0.0")
require.NoError(t, err)
_, err = os.Stat(pluginDir)
require.ErrorIs(t, err, os.ErrNotExist)
})
}