verstak-desktop/internal/core/permissions/registry.go

86 lines
3.3 KiB
Go

// Package permissions provides a registry for plugin permissions.
package permissions
import (
"sort"
"sync"
)
// Entry describes a known permission.
type Entry struct {
Name string `json:"name"`
Description string `json:"description"`
Dangerous bool `json:"dangerous"`
}
// Registry tracks known permissions and their safety levels.
type Registry struct {
mu sync.RWMutex
permissions map[string]Entry
}
// NewRegistry creates a new permissions registry.
func NewRegistry() *Registry {
r := &Registry{
permissions: make(map[string]Entry),
}
r.registerDefaults()
return r
}
func (r *Registry) registerDefaults() {
defaults := []Entry{
{Name: "vault.read", Description: "Read vault files and metadata", Dangerous: false},
{Name: "vault.write", Description: "Write vault files and metadata", Dangerous: true},
{Name: "vault.watch", Description: "Watch vault file changes", Dangerous: false},
{Name: "files.read", Description: "List files and read text files through the vault Files API", Dangerous: false},
{Name: "files.write", Description: "Create folders, write text files, and move paths through the vault Files API", Dangerous: true},
{Name: "files.delete", Description: "Trash vault files and folders through the vault Files API", Dangerous: true},
{Name: "storage.namespace", Description: "Read/write plugin's own storage namespace", Dangerous: false},
{Name: "storage.migrations", Description: "Run database migrations in plugin namespace", Dangerous: false},
{Name: "events.publish", Description: "Publish events to the event bus", Dangerous: false},
{Name: "events.subscribe", Description: "Subscribe to events on the event bus", Dangerous: false},
{Name: "ui.register", Description: "Register UI components and contributions", Dangerous: false},
{Name: "commands.register", Description: "Register command palette commands", Dangerous: false},
{Name: "workbench.open", Description: "Request Workbench open/edit routing for vault resources", Dangerous: false},
{Name: "network.local", Description: "Connect to localhost network services", Dangerous: false},
{Name: "network.remote", Description: "Connect to remote network services", Dangerous: true},
{Name: "process.spawn", Description: "Spawn external processes", Dangerous: true},
{Name: "secrets.read", Description: "Read secrets from the secret store", Dangerous: true},
{Name: "secrets.write", Description: "Write secrets to the secret store", Dangerous: true},
{Name: "sync.participate", Description: "Participate in vault sync", Dangerous: true},
}
for _, e := range defaults {
r.permissions[e.Name] = e
}
}
// Get returns permission info by name.
func (r *Registry) Get(name string) (Entry, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
e, ok := r.permissions[name]
return e, ok
}
// IsDangerous checks if a permission is marked dangerous.
func (r *Registry) IsDangerous(name string) bool {
e, ok := r.Get(name)
return ok && e.Dangerous
}
// List returns all known permissions, sorted by name.
func (r *Registry) List() []Entry {
r.mu.RLock()
defer r.mu.RUnlock()
entries := make([]Entry, 0, len(r.permissions))
for _, e := range r.permissions {
entries = append(entries, e)
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].Name < entries[j].Name
})
return entries
}