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
|
// Unregister all non-core capabilities
|
||||||
a.capRegistry.UnregisterAll()
|
a.capRegistry.UnregisterAll()
|
||||||
|
|
||||||
// Re-register core capabilities
|
// Re-register the same core capabilities as initial startup. Keeping this
|
||||||
coreCaps := []string{
|
// list in the capability package prevents a plugin reload from dropping a
|
||||||
"verstak/core/plugin-manager/v1",
|
// required capability such as native notifications.
|
||||||
"verstak/core/capability-registry/v1",
|
if err := a.capRegistry.Register(capability.CorePluginID, capability.CorePlatformCapabilities()); err != nil {
|
||||||
"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 {
|
|
||||||
log.Printf("[api] ReloadPlugins: failed to re-register core capabilities: %v", err)
|
log.Printf("[api] ReloadPlugins: failed to re-register core capabilities: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-register vault capability if vault is open
|
// Re-register vault capability if vault is open
|
||||||
if a.vault != nil && a.vault.GetVaultStatus() == vault.StatusOpen {
|
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)
|
log.Printf("[api] ReloadPlugins: failed to re-register vault capability: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-register workspace capability if workspace is initialized
|
// Re-register workspace capability if workspace is initialized
|
||||||
if a.workspace != nil && a.workspace.IsInitialized() {
|
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)
|
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) {
|
func TestDomReadyInitializesNotificationsBeforeScheduler(t *testing.T) {
|
||||||
oldInitialize := initializeNativeNotifications
|
oldInitialize := initializeNativeNotifications
|
||||||
defer func() { initializeNativeNotifications = oldInitialize }()
|
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 (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/verstak/verstak-desktop/internal/core/capability"
|
"github.com/verstak/verstak-desktop/internal/core/capability"
|
||||||
)
|
)
|
||||||
|
|
||||||
// coreCapabilities lists the 5 core capabilities that the platform registers
|
// registerCoreCapabilities registers the desktop's core capabilities on a registry.
|
||||||
// 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.
|
|
||||||
func registerCoreCapabilities(t *testing.T, reg *capability.Registry) {
|
func registerCoreCapabilities(t *testing.T, reg *capability.Registry) {
|
||||||
t.Helper()
|
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)
|
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
|
// TestLifecycle_MissingRequiredCapability verifies that when the required
|
||||||
// capability is NOT registered, CheckRequired reports it as missing and the
|
// capability is NOT registered, CheckRequired reports it as missing and the
|
||||||
// plugin status should be set to StatusMissingRequiredCapability.
|
// plugin status should be set to StatusMissingRequiredCapability.
|
||||||
|
|
|
||||||
13
main.go
13
main.go
|
|
@ -86,17 +86,8 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Register Core Capabilities ─────────────────────────
|
// ─── Register Core Capabilities ─────────────────────────
|
||||||
corePluginID := "verstak-desktop"
|
corePluginID := capability.CorePluginID
|
||||||
coreCaps := []string{
|
coreCaps := capability.CorePlatformCapabilities()
|
||||||
"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",
|
|
||||||
}
|
|
||||||
if err := capRegistry.Register(corePluginID, coreCaps); err != nil {
|
if err := capRegistry.Register(corePluginID, coreCaps); err != nil {
|
||||||
log.Fatalf("[main] failed to register core capabilities: %v", err)
|
log.Fatalf("[main] failed to register core capabilities: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ fi
|
||||||
echo "=== verstak desktop Linux amd64 bundle ==="
|
echo "=== verstak desktop Linux amd64 bundle ==="
|
||||||
(cd "$OFFICIAL_PLUGINS" && ./scripts/build.sh)
|
(cd "$OFFICIAL_PLUGINS" && ./scripts/build.sh)
|
||||||
"$ROOT/scripts/install-dev-plugins.sh"
|
"$ROOT/scripts/install-dev-plugins.sh"
|
||||||
|
(cd "$ROOT" && go test ./internal/core/plugin -run TestBundledOfficialPluginRequirementsResolve -count=1)
|
||||||
"$ROOT/scripts/build.sh"
|
"$ROOT/scripts/build.sh"
|
||||||
|
|
||||||
BINARY="$ROOT/build/bin/verstak-desktop"
|
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
|
echo "Windows plugin packages were not produced: $WINDOWS_PLUGIN_DIST" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
# Wails' -compiler option selects a Go binary, not a C compiler. Cross-CGO
|
||||||
# therefore has to be supplied through the standard Go environment instead.
|
# 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"
|
grep -Fq 'package-windows-portable.sh' "$ROOT/scripts/release.sh"
|
||||||
git -C "$ROOT" check-ignore -q verstak-desktop-res.syso
|
git -C "$ROOT" check-ignore -q verstak-desktop-res.syso
|
||||||
grep -Fq 'chmod -R a+rX' "$ROOT/scripts/build-linux-bundle.sh"
|
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"
|
echo "desktop package script contracts passed"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue