Skip to content

Commit

Permalink
pathpolicy: move PathTrie to a generic
Browse files Browse the repository at this point in the history
With generics support in go it seems like a good idea to move the
`PathTrie` to a generic.
  • Loading branch information
mvo5 authored and ondrejbudai committed Aug 12, 2024
1 parent 7964ba1 commit a1ebe54
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 39 deletions.
20 changes: 7 additions & 13 deletions pkg/pathpolicy/path_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@ type PathPolicy struct {
Exact bool // require and exact match, no subdirs
}

type PathPolicies = PathTrie
type PathPolicies struct {
pathTrie *PathTrie[PathPolicy]
}

// Create a new PathPolicies trie from a map of path to PathPolicy
func NewPathPolicies(entries map[string]PathPolicy) *PathPolicies {

noType := make(map[string]interface{}, len(entries))

for k, v := range entries {
noType[k] = v
return &PathPolicies{
pathTrie: NewPathTrieFromMap[PathPolicy](entries),
}

return NewPathTrieFromMap(noType)
}

// Check a given path against the PathPolicies
Expand All @@ -36,11 +33,8 @@ func (pol *PathPolicies) Check(fsPath string) error {
return fmt.Errorf("path %q must be canonical", fsPath)
}

node, left := pol.Lookup(fsPath)
policy, ok := node.Payload.(PathPolicy)
if !ok {
panic("programming error: invalid path trie payload")
}
node, left := pol.pathTrie.Lookup(fsPath)
policy := node.Payload

// 1) path is explicitly not allowed or
// 2) a subpath was match but an explicit match is required
Expand Down
28 changes: 14 additions & 14 deletions pkg/pathpolicy/path_tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@ func TestNewPathTrieFromMap(t *testing.T) {
assert := assert.New(t)

type testCase struct {
entries map[string]interface{}
trie *PathTrie
entries map[string]*int
trie *PathTrie[*int]
}

tests := []testCase{
{
entries: map[string]interface{}{},
trie: &PathTrie{
entries: map[string]*int{},
trie: &PathTrie[*int]{
Name: []string{},
},
},
{
entries: map[string]interface{}{
entries: map[string]*int{
"/": common.ToPtr(1),
},
trie: &PathTrie{
trie: &PathTrie[*int]{
Name: []string{},
Payload: common.ToPtr(1),
},
},
{
entries: map[string]interface{}{
entries: map[string]*int{
"/": common.ToPtr(1),
"/var": common.ToPtr(2),
"/var/lib/chrony": common.ToPtr(3),
Expand All @@ -43,14 +43,14 @@ func TestNewPathTrieFromMap(t *testing.T) {
"/boot": common.ToPtr(7),
"/boot/efi": common.ToPtr(8),
},
trie: &PathTrie{
trie: &PathTrie[*int]{
Name: []string{},
Payload: common.ToPtr(1),
Paths: []*PathTrie{
Paths: []*PathTrie[*int]{
{
Name: []string{"boot"},
Payload: common.ToPtr(7),
Paths: []*PathTrie{
Paths: []*PathTrie[*int]{
{
Name: []string{"efi"},
Payload: common.ToPtr(8),
Expand All @@ -60,11 +60,11 @@ func TestNewPathTrieFromMap(t *testing.T) {
{
Name: []string{"var"},
Payload: common.ToPtr(2),
Paths: []*PathTrie{
Paths: []*PathTrie[*int]{
{
Name: []string{"lib", "chrony"},
Payload: common.ToPtr(3),
Paths: []*PathTrie{
Paths: []*PathTrie[*int]{
{
Name: []string{"logs"},
Payload: common.ToPtr(4),
Expand All @@ -74,7 +74,7 @@ func TestNewPathTrieFromMap(t *testing.T) {
{
Name: []string{"lib", "osbuild"},
Payload: common.ToPtr(5),
Paths: []*PathTrie{
Paths: []*PathTrie[*int]{
{
Name: []string{"store", "cache"},
Payload: common.ToPtr(6),
Expand All @@ -98,7 +98,7 @@ func TestNewPathTrieFromMap(t *testing.T) {
func TestPathTrieLookup(t *testing.T) {
assert := assert.New(t)

entries := map[string]interface{}{
entries := map[string]string{
"/": "/",
"/boot": "/boot",
"/boot/efi": "/boot/efi",
Expand Down
24 changes: 12 additions & 12 deletions pkg/pathpolicy/path_trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ func pathTrieSplitPath(path string) []string {
return strings.Split(path, "/")
}

type PathTrie struct {
type PathTrie[T any] struct {
Name []string
Paths []*PathTrie
Payload interface{}
Paths []*PathTrie[T]
Payload T
}

// match checks if the given trie is a prefix of path
func (trie *PathTrie) match(path []string) bool {
func (trie *PathTrie[T]) match(path []string) bool {
if len(trie.Name) > len(path) {
return false
}
Expand All @@ -37,12 +37,12 @@ func (trie *PathTrie) match(path []string) bool {
return true
}

func (trie *PathTrie) get(path []string) (*PathTrie, []string) {
func (trie *PathTrie[T]) get(path []string) (*PathTrie[T], []string) {
if len(path) < 1 {
panic("programming error: expected root node")
}

var node *PathTrie
var node *PathTrie[T]
for i := range trie.Paths {
if trie.Paths[i].match(path) {
node = trie.Paths[i]
Expand All @@ -67,11 +67,11 @@ func (trie *PathTrie) get(path []string) (*PathTrie, []string) {
return node.get(path[prefix:])
}

func (trie *PathTrie) add(path []string) *PathTrie {
node := &PathTrie{Name: path}
func (trie *PathTrie[T]) add(path []string) *PathTrie[T] {
node := &PathTrie[T]{Name: path}

if trie.Paths == nil {
trie.Paths = make([]*PathTrie, 0, 1)
trie.Paths = make([]*PathTrie[T], 0, 1)
}

trie.Paths = append(trie.Paths, node)
Expand All @@ -81,8 +81,8 @@ func (trie *PathTrie) add(path []string) *PathTrie {

// Construct a new trie from a map of paths to their payloads.
// Returns the root node of the trie.
func NewPathTrieFromMap(entries map[string]interface{}) *PathTrie {
root := &PathTrie{Name: []string{}}
func NewPathTrieFromMap[T any](entries map[string]T) *PathTrie[T] {
root := &PathTrie[T]{Name: []string{}}

keys := make([]string, 0, len(entries))
for k := range entries {
Expand All @@ -107,7 +107,7 @@ func NewPathTrieFromMap(entries map[string]interface{}) *PathTrie {
// Lookup returns the node that is the prefix of path and
// the unmatched path segment. Must be called on the root
// trie node.
func (root *PathTrie) Lookup(path string) (*PathTrie, []string) {
func (root *PathTrie[T]) Lookup(path string) (*PathTrie[T], []string) {

if len(root.Name) != 0 {
panic("programming error: lookup on non-root trie node")
Expand Down

0 comments on commit a1ebe54

Please sign in to comment.