mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-30 16:05:30 +00:00
* feat(mcp): add Panel MCP task configuration and website binding structures * fix(mcp): correct variable assignment in mcpWebsiteDomain function
99 lines
2.3 KiB
Go
99 lines
2.3 KiB
Go
// Package taskscope separates task visibility and executor ownership from task storage.
|
|
package taskscope
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
"sync/atomic"
|
|
)
|
|
|
|
type Rule struct {
|
|
Scope string
|
|
Restricted bool
|
|
ExternalExecutor bool
|
|
}
|
|
|
|
type policy struct{ rules []Rule }
|
|
|
|
var configured atomic.Pointer[policy]
|
|
|
|
var ErrUnavailable = errors.New("task scope policy is unavailable")
|
|
|
|
func Configure(rules ...Rule) error {
|
|
copyRules := append([]Rule(nil), rules...)
|
|
if len(copyRules) == 0 {
|
|
return ErrUnavailable
|
|
}
|
|
sort.Slice(copyRules, func(i, j int) bool { return copyRules[i].Scope < copyRules[j].Scope })
|
|
for i, rule := range copyRules {
|
|
if rule.Scope == "" || strings.TrimSpace(rule.Scope) != rule.Scope || strings.ContainsAny(rule.Scope, "\x00\r\n") ||
|
|
i > 0 && copyRules[i-1].Scope == rule.Scope {
|
|
return errors.New("invalid task scope policy")
|
|
}
|
|
}
|
|
next := &policy{rules: copyRules}
|
|
if configured.CompareAndSwap(nil, next) {
|
|
return nil
|
|
}
|
|
if !slices.Equal(configured.Load().rules, next.rules) {
|
|
return errors.New("task scope policy is already configured")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ReadExclusions(granted ...string) ([]string, error) {
|
|
p := configured.Load()
|
|
if p == nil {
|
|
return nil, ErrUnavailable
|
|
}
|
|
allowed := make(map[string]bool, len(granted))
|
|
for _, scope := range granted {
|
|
found := false
|
|
for _, rule := range p.rules {
|
|
if rule.Scope == scope && rule.Restricted {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found || allowed[scope] {
|
|
return nil, errors.New("invalid task scope grant")
|
|
}
|
|
allowed[scope] = true
|
|
}
|
|
var excluded []string
|
|
for _, rule := range p.rules {
|
|
if rule.Restricted && !allowed[rule.Scope] {
|
|
excluded = append(excluded, rule.Scope)
|
|
}
|
|
}
|
|
return excluded, nil
|
|
}
|
|
|
|
func RecoveryExclusions() ([]string, error) {
|
|
p := configured.Load()
|
|
if p == nil {
|
|
return nil, ErrUnavailable
|
|
}
|
|
var excluded []string
|
|
for _, rule := range p.rules {
|
|
if rule.ExternalExecutor {
|
|
excluded = append(excluded, rule.Scope)
|
|
}
|
|
}
|
|
return excluded, nil
|
|
}
|
|
|
|
type grantKey struct{}
|
|
|
|
func WithGrants(ctx context.Context, granted ...string) context.Context {
|
|
return context.WithValue(ctx, grantKey{}, append([]string(nil), granted...))
|
|
}
|
|
|
|
func Grants(ctx context.Context) []string {
|
|
granted, _ := ctx.Value(grantKey{}).([]string)
|
|
return append([]string(nil), granted...)
|
|
}
|