-
Notifications
You must be signed in to change notification settings - Fork 311
Simplify pkg/permissions: extract helper, reduce type cases, remove redundant checks #2183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,6 @@ package permissions | |
| import ( | ||
| "fmt" | ||
| "path/filepath" | ||
| "strconv" | ||
| "strings" | ||
|
|
||
| "github.com/docker/docker-agent/pkg/config/latest" | ||
|
|
@@ -85,30 +84,34 @@ func (c *Checker) Check(toolName string) Decision { | |
| // (e.g. read-only tools). Note that --yolo mode takes precedence over ForceAsk. | ||
| func (c *Checker) CheckWithArgs(toolName string, args map[string]any) Decision { | ||
| // Deny patterns are checked first - they take priority | ||
| for _, pattern := range c.denyPatterns { | ||
| if matchToolPattern(pattern, toolName, args) { | ||
| return Deny | ||
| } | ||
| if matchAny(c.denyPatterns, toolName, args) { | ||
| return Deny | ||
| } | ||
|
|
||
| // Allow patterns are checked second | ||
| for _, pattern := range c.allowPatterns { | ||
| if matchToolPattern(pattern, toolName, args) { | ||
| return Allow | ||
| } | ||
| if matchAny(c.allowPatterns, toolName, args) { | ||
| return Allow | ||
| } | ||
|
|
||
| // Explicit ask patterns override auto-approval (e.g. read-only hints) | ||
| for _, pattern := range c.askPatterns { | ||
| if matchToolPattern(pattern, toolName, args) { | ||
| return ForceAsk | ||
| } | ||
| if matchAny(c.askPatterns, toolName, args) { | ||
| return ForceAsk | ||
| } | ||
|
|
||
| // Default is Ask | ||
| return Ask | ||
| } | ||
|
|
||
| // matchAny reports whether any pattern in the list matches the tool name and args. | ||
| func matchAny(patterns []string, toolName string, args map[string]any) bool { | ||
| for _, pattern := range patterns { | ||
| if matchToolPattern(pattern, toolName, args) { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| // IsEmpty returns true if no permissions are configured | ||
| func (c *Checker) IsEmpty() bool { | ||
| return len(c.allowPatterns) == 0 && len(c.askPatterns) == 0 && len(c.denyPatterns) == 0 | ||
|
|
@@ -176,12 +179,7 @@ func matchToolPattern(pattern, toolName string, args map[string]any) bool { | |
| return true | ||
| } | ||
|
|
||
| // If pattern has argument conditions but no args provided, no match | ||
| if args == nil { | ||
| return false | ||
| } | ||
|
|
||
| // All argument patterns must match | ||
| // All argument patterns must match (indexing a nil args map is safe in Go) | ||
| for argName, argPattern := range argPatterns { | ||
| argValue, exists := args[argName] | ||
| if !exists { | ||
|
|
@@ -203,16 +201,9 @@ func argToString(v any) string { | |
| switch val := v.(type) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Low Severity: Behavioral change for custom types The simplified For example, a custom type wrapping int with a This is unlikely in practice (tool args are typically JSON-unmarshaled primitives), but worth noting as a subtle behavioral change. |
||
| case string: | ||
| return val | ||
| case bool: | ||
| return strconv.FormatBool(val) | ||
| case float64: | ||
| // JSON numbers are float64 - format without trailing zeros | ||
| if val == float64(int64(val)) { | ||
| return strconv.FormatInt(int64(val), 10) | ||
| } | ||
| // JSON numbers are float64 - use %g for shortest representation | ||
| return fmt.Sprintf("%g", val) | ||
| case int, int64: | ||
| return fmt.Sprintf("%d", val) | ||
| default: | ||
| return fmt.Sprintf("%v", v) | ||
| } | ||
|
|
@@ -237,10 +228,11 @@ func matchGlob(pattern, value string) bool { | |
|
|
||
| // Handle trailing wildcard for prefix matching | ||
| // This allows "sudo*" to match "sudo rm -rf /" | ||
| if strings.HasSuffix(pattern, "*") && !strings.HasSuffix(pattern, "\\*") { | ||
| if strings.HasSuffix(pattern, "*") { | ||
| prefix := pattern[:len(pattern)-1] | ||
| // If prefix contains no other glob characters, do simple prefix match | ||
| if !strings.ContainsAny(prefix, "*?[") { | ||
| // If prefix contains no other glob characters, do simple prefix match. | ||
| // Including \ catches escaped asterisks (e.g. "foo\*"). | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Low Severity: Overly broad backslash check The new code includes backslash in For example, This is safe (filepath.Match handles escaping correctly), but more conservative than before. The comment could be clearer about this trade-off. |
||
| if !strings.ContainsAny(prefix, `*?[\`) { | ||
| return strings.HasPrefix(value, prefix) | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Low Severity: Misleading comment
The comment states "indexing a nil args map is safe in Go", but the code doesn't index a nil map—it iterates over
argPatternsand reads fromargs. Whenargsis nil andargPatternsis non-empty, theexistscheck at line 184 returns false, causing an early return at line 185.The behavior is correct (matches the old explicit nil check), but the comment is misleading. Consider clarifying:
// All argument patterns must match (reading from a nil map returns zero value and false for exists check)