Conversation
- Add tests for ACL file detection, path manipulation, and symlink security - Add tests for access control levels and bit flag operations - Add tests for rule pattern matching and access validation - Add tests for ruleset loading and validation - Add tests for rate limiting and resource constraints - Add tests for ACL cache operations including concurrency - Add tests for server ACL access levels
There was a problem hiding this comment.
Pull Request Overview
This PR enhances security by rejecting symlinked ACL files, fixes rule management in the tree and node structures, and increases test coverage across ACL and permissions components.
- Prevents symlink-based ACL loading in both
ExistsandLoadFromFile - Improves cache tests to cover basic ops, prefix deletion, version behavior, concurrency, and memory usage
- Adds comprehensive tests for rule set loading, saving, and default injection
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/server/acl/level_test.go | Adds unit tests for AccessLevel.String() and bitwise operations |
| internal/server/acl/cache_test.go | Expands tests for ACLCache (Get/Set/Delete, DeletePrefix, concurrency, memory) |
| internal/aclspec/ruleset.go | Enforces symlink rejection in LoadFromFile |
| internal/aclspec/aclspec.go | Switches to Lstat and rejects symlinks in Exists |
| internal/aclspec/ruleset_test.go | New tests for YAML load/save, default rule injection, and error cases |
| internal/aclspec/aclspec_test.go | New tests for ACL file detection, path helpers, and symlink security |
Comments suppressed due to low confidence (1)
internal/aclspec/ruleset.go:44
- You use
fmt.Errorfon the next line, but I don’t seefmtimported; addimport "fmt"so the code compiles.
if stat.Mode()&os.ModeSymlink != 0 {
| aclPath := AsACLPath(path) | ||
| stat, err := os.Stat(aclPath) | ||
| stat, err := os.Lstat(aclPath) // Use Lstat to not follow symlinks | ||
| if os.IsNotExist(err) { |
There was a problem hiding this comment.
Errors other than IsNotExist are currently ignored, potentially masking permission or I/O errors. Consider checking if err != nil { return false } immediately after Lstat before continuing.
| if os.IsNotExist(err) { | |
| if err != nil { | |
| if os.IsNotExist(err) { | |
| return false | |
| } | |
| // Handle other errors (e.g., permission or I/O errors) |
| // Test concurrent Get operations | ||
| for i := 0; i < numGoroutines; i++ { | ||
| wg.Add(1) | ||
| go func(id int) { |
There was a problem hiding this comment.
[nitpick] Calling assert (or using t) directly inside goroutines can lead to data races on testing.T. Collect errors or use channels and perform assertions after all goroutines complete.
Core Changes:
Terminal node enforcement: Prevent child rulesets from being added under terminal nodes for proper security boundaries
Symlink security: Reject symlinked ACL files in Exists() and LoadFromFile() to prevent security vulnerabilities
Rule removal fix: RemoveRuleSet now only clears rules from target node while preserving child nodes, preventing accidental data loss
Rule clearing: SetRules properly clears existing rules when passed nil/empty ruleset
Technical Details:
tree.go: Add ErrTerminalNodeExists, validate terminal nodes in AddRuleSet, rewrite RemoveRuleSet to preserve children
node.go: Fix SetRules to clear rules when nil/empty input provided
aclspec.go: Replace os.Stat with os.Lstat and add symlink rejection in Exists()
ruleset.go: Add symlink validation in LoadFromFile() with descriptive error messages
Tests added to internal/server/acl and internal/aclspec packages to increase coverage and validate new security behaviors.