Plugins: Add Plugin FS abstraction (#63734)

* unexport pluginDir from dto

* first pass

* tidy

* naming + add mutex

* add dupe checking

* fix func typo

* interface + move logic from renderer

* remote finder

* remote signing

* fix tests

* tidy up

* tidy markdown logic

* split changes

* fix tests

* slim interface down

* fix status code

* tidy exec path func

* fixup

* undo changes

* remove unused func

* remove unused func

* fix goimports

* fetch remotely

* simultaneous support

* fix linter

* use var

* add exception for gosec warning

* fixup

* fix tests

* tidy

* rework cfg pattern

* simplify

* PR feedback

* fix dupe field

* remove g304 nolint

* apply PR feedback

* remove unnecessary gosec nolint

* fix finder loop and update comment

* fix map alloc

* fix test

* remove commented code
This commit is contained in:
Will Browne
2023-03-07 15:47:02 +00:00
committed by GitHub
parent 380138f57b
commit 68df83c86d
22 changed files with 1344 additions and 870 deletions

View File

@ -6,8 +6,7 @@ import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"path"
"runtime"
"strings"
@ -26,8 +25,8 @@ var ErrFileNotExist = errors.New("file does not exist")
type Plugin struct {
JSONData
PluginDir string
Class Class
FS FS
Class Class
// App fields
IncludedInAppID string
@ -55,8 +54,8 @@ type Plugin struct {
type PluginDTO struct {
JSONData
fs FS
logger log.Logger
pluginDir string
supportsStreaming bool
Class Class
@ -81,6 +80,10 @@ func (p PluginDTO) SupportsStreaming() bool {
return p.supportsStreaming
}
func (p PluginDTO) Base() string {
return p.fs.Base()
}
func (p PluginDTO) IsApp() bool {
return p.Type == App
}
@ -96,21 +99,15 @@ func (p PluginDTO) File(name string) (fs.File, error) {
return nil, err
}
absPluginDir, err := filepath.Abs(p.pluginDir)
if p.fs == nil {
return nil, ErrFileNotExist
}
f, err := p.fs.Open(cleanPath)
if err != nil {
return nil, err
}
absFilePath := filepath.Join(absPluginDir, cleanPath)
// Wrapping in filepath.Clean to properly handle
// gosec G304 Potential file inclusion via variable rule.
f, err := os.Open(filepath.Clean(absFilePath))
if err != nil {
if os.IsNotExist(err) {
return nil, ErrFileNotExist
}
return nil, err
}
return f, nil
}
@ -337,6 +334,18 @@ func (p *Plugin) Client() (PluginClient, bool) {
}
func (p *Plugin) ExecutablePath() string {
if p.IsRenderer() {
return p.executablePath("plugin_start")
}
if p.IsSecretsManager() {
return p.executablePath("secrets_plugin_start")
}
return p.executablePath(p.Executable)
}
func (p *Plugin) executablePath(f string) string {
os := strings.ToLower(runtime.GOOS)
arch := runtime.GOARCH
extension := ""
@ -344,15 +353,7 @@ func (p *Plugin) ExecutablePath() string {
if os == "windows" {
extension = ".exe"
}
if p.IsRenderer() {
return filepath.Join(p.PluginDir, fmt.Sprintf("%s_%s_%s%s", "plugin_start", os, strings.ToLower(arch), extension))
}
if p.IsSecretsManager() {
return filepath.Join(p.PluginDir, fmt.Sprintf("%s_%s_%s%s", "secrets_plugin_start", os, strings.ToLower(arch), extension))
}
return filepath.Join(p.PluginDir, fmt.Sprintf("%s_%s_%s%s", p.Executable, os, strings.ToLower(arch), extension))
return path.Join(p.FS.Base(), fmt.Sprintf("%s_%s_%s%s", f, os, strings.ToLower(arch), extension))
}
type PluginClient interface {
@ -366,9 +367,10 @@ type PluginClient interface {
func (p *Plugin) ToDTO() PluginDTO {
return PluginDTO{
logger: p.Logger(),
pluginDir: p.PluginDir,
JSONData: p.JSONData,
fs: p.FS,
supportsStreaming: p.client != nil && p.client.(backend.StreamHandler) != nil,
Class: p.Class,
JSONData: p.JSONData,
IncludedInAppID: p.IncludedInAppID,
DefaultNavURL: p.DefaultNavURL,
Pinned: p.Pinned,
@ -378,7 +380,6 @@ func (p *Plugin) ToDTO() PluginDTO {
SignatureError: p.SignatureError,
Module: p.Module,
BaseURL: p.BaseURL,
supportsStreaming: p.client != nil && p.client.(backend.StreamHandler) != nil,
}
}
@ -387,7 +388,11 @@ func (p *Plugin) StaticRoute() *StaticRoute {
return nil
}
return &StaticRoute{Directory: p.PluginDir, PluginID: p.ID}
if p.FS == nil {
return nil
}
return &StaticRoute{Directory: p.FS.Base(), PluginID: p.ID}
}
func (p *Plugin) IsRenderer() bool {
@ -414,15 +419,6 @@ func (p *Plugin) IsExternalPlugin() bool {
return p.Class == External
}
func (p *Plugin) Manifest() []byte {
d, err := os.ReadFile(filepath.Join(p.PluginDir, "MANIFEST.txt"))
if err != nil {
return []byte{}
}
return d
}
type Class string
const (