130 lines
3.8 KiB
Go
130 lines
3.8 KiB
Go
package scopes
|
|
|
|
import "github.com/github/github-mcp-server/pkg/inventory"
|
|
|
|
// ToolScopeMap maps tool names to their scope requirements.
|
|
type ToolScopeMap map[string]*ToolScopeInfo
|
|
|
|
// ToolScopeInfo contains scope information for a single tool.
|
|
type ToolScopeInfo struct {
|
|
// RequiredScopes contains the scopes that are directly required by this tool.
|
|
RequiredScopes []string
|
|
|
|
// AcceptedScopes contains all scopes that satisfy the requirements (including parent scopes).
|
|
AcceptedScopes []string
|
|
}
|
|
|
|
// globalToolScopeMap is populated from inventory when SetToolScopeMapFromInventory is called
|
|
var globalToolScopeMap ToolScopeMap
|
|
|
|
// SetToolScopeMapFromInventory builds and stores a tool scope map from an inventory.
|
|
// This should be called after building the inventory to make scopes available for middleware.
|
|
func SetToolScopeMapFromInventory(inv *inventory.Inventory) {
|
|
globalToolScopeMap = GetToolScopeMapFromInventory(inv)
|
|
}
|
|
|
|
// SetGlobalToolScopeMap sets the global tool scope map directly.
|
|
// This is useful for testing when you don't have a full inventory.
|
|
func SetGlobalToolScopeMap(m ToolScopeMap) {
|
|
globalToolScopeMap = m
|
|
}
|
|
|
|
// GetToolScopeMap returns the global tool scope map.
|
|
// Returns an empty map if SetToolScopeMapFromInventory hasn't been called yet.
|
|
func GetToolScopeMap() (ToolScopeMap, error) {
|
|
if globalToolScopeMap == nil {
|
|
return make(ToolScopeMap), nil
|
|
}
|
|
return globalToolScopeMap, nil
|
|
}
|
|
|
|
// GetToolScopeInfo returns scope information for a specific tool from the global scope map.
|
|
func GetToolScopeInfo(toolName string) (*ToolScopeInfo, error) {
|
|
m, err := GetToolScopeMap()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m[toolName], nil
|
|
}
|
|
|
|
// GetToolScopeMapFromInventory builds a tool scope map from an inventory.
|
|
// This extracts scope information from ServerTool.RequiredScopes and ServerTool.AcceptedScopes.
|
|
func GetToolScopeMapFromInventory(inv *inventory.Inventory) ToolScopeMap {
|
|
result := make(ToolScopeMap)
|
|
|
|
// Get all tools from the inventory (both enabled and disabled)
|
|
// We need all tools for scope checking purposes
|
|
allTools := inv.AllTools()
|
|
for i := range allTools {
|
|
tool := &allTools[i]
|
|
if len(tool.RequiredScopes) > 0 || len(tool.AcceptedScopes) > 0 {
|
|
result[tool.Tool.Name] = &ToolScopeInfo{
|
|
RequiredScopes: tool.RequiredScopes,
|
|
AcceptedScopes: tool.AcceptedScopes,
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// HasAcceptedScope checks if any of the provided user scopes satisfy the tool's requirements.
|
|
func (t *ToolScopeInfo) HasAcceptedScope(userScopes ...string) bool {
|
|
if t == nil || len(t.AcceptedScopes) == 0 {
|
|
return true // No scopes required
|
|
}
|
|
|
|
userScopeSet := make(map[string]bool)
|
|
for _, scope := range userScopes {
|
|
userScopeSet[scope] = true
|
|
}
|
|
|
|
for _, scope := range t.AcceptedScopes {
|
|
if userScopeSet[scope] {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// MissingScopes returns the required scopes that are not present in the user's scopes.
|
|
func (t *ToolScopeInfo) MissingScopes(userScopes ...string) []string {
|
|
if t == nil || len(t.RequiredScopes) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Create a set of user scopes for O(1) lookup
|
|
userScopeSet := make(map[string]bool, len(userScopes))
|
|
for _, s := range userScopes {
|
|
userScopeSet[s] = true
|
|
}
|
|
|
|
// Check if any accepted scope is present
|
|
hasAccepted := false
|
|
for _, scope := range t.AcceptedScopes {
|
|
if userScopeSet[scope] {
|
|
hasAccepted = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if hasAccepted {
|
|
return nil // User has sufficient scopes
|
|
}
|
|
|
|
// Return required scopes as the minimum needed
|
|
missing := make([]string, len(t.RequiredScopes))
|
|
copy(missing, t.RequiredScopes)
|
|
return missing
|
|
}
|
|
|
|
// GetRequiredScopesSlice returns the required scopes as a slice of strings.
|
|
func (t *ToolScopeInfo) GetRequiredScopesSlice() []string {
|
|
if t == nil {
|
|
return nil
|
|
}
|
|
scopes := make([]string, len(t.RequiredScopes))
|
|
copy(scopes, t.RequiredScopes)
|
|
return scopes
|
|
}
|