fix: validate bundled plugin requirements
This commit is contained in:
parent
680846da72
commit
fc82b3e6b1
|
|
@ -1064,30 +1064,23 @@ func (a *App) ReloadPlugins() (int, string) {
|
|||
// Unregister all non-core capabilities
|
||||
a.capRegistry.UnregisterAll()
|
||||
|
||||
// Re-register core capabilities
|
||||
coreCaps := []string{
|
||||
"verstak/core/plugin-manager/v1",
|
||||
"verstak/core/capability-registry/v1",
|
||||
"verstak/core/contribution-registry/v1",
|
||||
"verstak/core/permissions/v1",
|
||||
"verstak/core/events/v1",
|
||||
"verstak/core/files/v1",
|
||||
"verstak/core/workbench/v1",
|
||||
}
|
||||
if err := a.capRegistry.Register("verstak-desktop", coreCaps); err != nil {
|
||||
// Re-register the same core capabilities as initial startup. Keeping this
|
||||
// list in the capability package prevents a plugin reload from dropping a
|
||||
// required capability such as native notifications.
|
||||
if err := a.capRegistry.Register(capability.CorePluginID, capability.CorePlatformCapabilities()); err != nil {
|
||||
log.Printf("[api] ReloadPlugins: failed to re-register core capabilities: %v", err)
|
||||
}
|
||||
|
||||
// Re-register vault capability if vault is open
|
||||
if a.vault != nil && a.vault.GetVaultStatus() == vault.StatusOpen {
|
||||
if err := a.capRegistry.Register("verstak-desktop", []string{"verstak/core/vault/v1"}); err != nil {
|
||||
if err := a.capRegistry.Register(capability.CorePluginID, []string{"verstak/core/vault/v1"}); err != nil {
|
||||
log.Printf("[api] ReloadPlugins: failed to re-register vault capability: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Re-register workspace capability if workspace is initialized
|
||||
if a.workspace != nil && a.workspace.IsInitialized() {
|
||||
if err := a.capRegistry.Register("verstak-desktop", []string{"verstak/core/workspace/v1"}); err != nil {
|
||||
if err := a.capRegistry.Register(capability.CorePluginID, []string{"verstak/core/workspace/v1"}); err != nil {
|
||||
log.Printf("[api] ReloadPlugins: failed to re-register workspace capability: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,6 +225,19 @@ func TestReplaceAndClearPluginNotificationsStayWithinPluginNamespace(t *testing.
|
|||
}
|
||||
}
|
||||
|
||||
func TestReloadPluginsRestoresNotificationCoreCapability(t *testing.T) {
|
||||
app := &App{
|
||||
capRegistry: capability.NewRegistry(),
|
||||
contribRegistry: contribution.NewRegistry(),
|
||||
}
|
||||
|
||||
app.ReloadPlugins()
|
||||
|
||||
if !app.capRegistry.Has("verstak/core/notifications/v1") {
|
||||
t.Fatal("ReloadPlugins did not restore verstak/core/notifications/v1")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDomReadyInitializesNotificationsBeforeScheduler(t *testing.T) {
|
||||
oldInitialize := initializeNativeNotifications
|
||||
defer func() { initializeNativeNotifications = oldInitialize }()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package capability
|
||||
|
||||
const CorePluginID = "verstak-desktop"
|
||||
|
||||
var platformCapabilities = []string{
|
||||
"verstak/core/plugin-manager/v1",
|
||||
"verstak/core/capability-registry/v1",
|
||||
"verstak/core/contribution-registry/v1",
|
||||
"verstak/core/permissions/v1",
|
||||
"verstak/core/events/v1",
|
||||
"verstak/core/files/v1",
|
||||
"verstak/core/workbench/v1",
|
||||
"verstak/core/notifications/v1",
|
||||
}
|
||||
|
||||
// CorePlatformCapabilities returns a copy of the capabilities registered by
|
||||
// the desktop before dynamic plugins are resolved.
|
||||
func CorePlatformCapabilities() []string {
|
||||
return append([]string(nil), platformCapabilities...)
|
||||
}
|
||||
|
|
@ -3,25 +3,16 @@ package plugin
|
|||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/verstak/verstak-desktop/internal/core/capability"
|
||||
)
|
||||
|
||||
// coreCapabilities lists the 5 core capabilities that the platform registers
|
||||
// before any plugins are loaded.
|
||||
var coreCapabilities = []string{
|
||||
"verstak/core/plugin-manager/v1",
|
||||
"verstak/core/capability-registry/v1",
|
||||
"verstak/core/contribution-registry/v1",
|
||||
"verstak/core/permissions/v1",
|
||||
"verstak/core/events/v1",
|
||||
}
|
||||
|
||||
// registerCoreCapabilities registers the 5 core capabilities on a registry.
|
||||
// registerCoreCapabilities registers the desktop's core capabilities on a registry.
|
||||
func registerCoreCapabilities(t *testing.T, reg *capability.Registry) {
|
||||
t.Helper()
|
||||
if err := reg.Register("verstak-core", coreCapabilities); err != nil {
|
||||
if err := reg.Register(capability.CorePluginID, capability.CorePlatformCapabilities()); err != nil {
|
||||
t.Fatalf("failed to register core capabilities: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +67,43 @@ func TestLifecycle_CoreCapabilitiesRegisteredBeforePlugins(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBundledOfficialPluginRequirementsResolve(t *testing.T) {
|
||||
plugins, errs := DiscoverPlugins([]string{bundledPluginDir(t)})
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("discover bundled plugins: %v", errs)
|
||||
}
|
||||
|
||||
reg := capability.NewRegistry()
|
||||
registerCoreCapabilities(t, reg)
|
||||
ResolveLifecycle(plugins, reg, nil)
|
||||
|
||||
foundTodo := false
|
||||
for _, loaded := range plugins {
|
||||
if loaded.Manifest.ID == "verstak.todo" {
|
||||
foundTodo = true
|
||||
}
|
||||
if loaded.Status == StatusMissingRequiredCapability {
|
||||
t.Fatalf("bundled plugin %q is missing required capabilities: %s", loaded.Manifest.ID, loaded.Error)
|
||||
}
|
||||
}
|
||||
|
||||
if !foundTodo {
|
||||
t.Fatal("bundled Todo manifest was not discovered")
|
||||
}
|
||||
}
|
||||
|
||||
func bundledPluginDir(t *testing.T) string {
|
||||
t.Helper()
|
||||
if configured := os.Getenv("VERSTAK_RELEASE_PLUGIN_DIR"); configured != "" {
|
||||
return configured
|
||||
}
|
||||
_, sourceFile, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
t.Fatal("could not resolve lifecycle test path")
|
||||
}
|
||||
return filepath.Join(filepath.Dir(sourceFile), "../../../plugins")
|
||||
}
|
||||
|
||||
// TestLifecycle_MissingRequiredCapability verifies that when the required
|
||||
// capability is NOT registered, CheckRequired reports it as missing and the
|
||||
// plugin status should be set to StatusMissingRequiredCapability.
|
||||
|
|
|
|||
13
main.go
13
main.go
|
|
@ -86,17 +86,8 @@ func main() {
|
|||
}
|
||||
|
||||
// ─── Register Core Capabilities ─────────────────────────
|
||||
corePluginID := "verstak-desktop"
|
||||
coreCaps := []string{
|
||||
"verstak/core/plugin-manager/v1",
|
||||
"verstak/core/capability-registry/v1",
|
||||
"verstak/core/contribution-registry/v1",
|
||||
"verstak/core/permissions/v1",
|
||||
"verstak/core/events/v1",
|
||||
"verstak/core/files/v1",
|
||||
"verstak/core/workbench/v1",
|
||||
"verstak/core/notifications/v1",
|
||||
}
|
||||
corePluginID := capability.CorePluginID
|
||||
coreCaps := capability.CorePlatformCapabilities()
|
||||
if err := capRegistry.Register(corePluginID, coreCaps); err != nil {
|
||||
log.Fatalf("[main] failed to register core capabilities: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ fi
|
|||
echo "=== verstak desktop Linux amd64 bundle ==="
|
||||
(cd "$OFFICIAL_PLUGINS" && ./scripts/build.sh)
|
||||
"$ROOT/scripts/install-dev-plugins.sh"
|
||||
(cd "$ROOT" && go test ./internal/core/plugin -run TestBundledOfficialPluginRequirementsResolve -count=1)
|
||||
"$ROOT/scripts/build.sh"
|
||||
|
||||
BINARY="$ROOT/build/bin/verstak-desktop"
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ if [[ ! -d "$WINDOWS_PLUGIN_DIST" ]]; then
|
|||
echo "Windows plugin packages were not produced: $WINDOWS_PLUGIN_DIST" >&2
|
||||
exit 1
|
||||
fi
|
||||
VERSTAK_RELEASE_PLUGIN_DIR="$WINDOWS_PLUGIN_DIST" go test ./internal/core/plugin -run TestBundledOfficialPluginRequirementsResolve -count=1
|
||||
|
||||
# Wails' -compiler option selects a Go binary, not a C compiler. Cross-CGO
|
||||
# therefore has to be supplied through the standard Go environment instead.
|
||||
|
|
|
|||
|
|
@ -41,5 +41,7 @@ grep -Fq 'package-appimage.sh' "$ROOT/scripts/release.sh"
|
|||
grep -Fq 'package-windows-portable.sh' "$ROOT/scripts/release.sh"
|
||||
git -C "$ROOT" check-ignore -q verstak-desktop-res.syso
|
||||
grep -Fq 'chmod -R a+rX' "$ROOT/scripts/build-linux-bundle.sh"
|
||||
grep -Fq 'TestBundledOfficialPluginRequirementsResolve' "$ROOT/scripts/build-linux-bundle.sh"
|
||||
grep -Fq 'TestBundledOfficialPluginRequirementsResolve' "$ROOT/scripts/build-windows.sh"
|
||||
|
||||
echo "desktop package script contracts passed"
|
||||
|
|
|
|||
Loading…
Reference in New Issue