func populateAndVerifyPolicyDocument(
	policyDoc *types.PolicyDocument,
	tree types.ScopeTree,
	currScope types.PermissionScope,
	parentVerbs []types.APIVerb,
	reqScopes map[types.PermissionScope]*types.RequestAction,
	currMatchDocs map[types.PermissionScope]*types.PolicyDocument,
) (ok bool, matchDocs map[types.PermissionScope]*types.PolicyDocument) {
	if currMatchDocs == nil {
		currMatchDocs = make(map[types.PermissionScope]*types.PolicyDocument)
	}
	matchDocs = currMatchDocs
	currDoc := policyDoc
	if policyDoc == nil {
		currDoc = &types.PolicyDocument{
			Scope: currScope,
			Verbs: parentVerbs,
		}
	}
	subTree, ok := tree[currDoc.Scope]
	if !ok || currDoc.Scope != currScope {
		return false, matchDocs
	}
	processedChildren := 0
	for currScope := range subTree {
		if _, exists := currDoc.Children[currScope]; exists {
			processedChildren++
		}
		ok, matchDocs = populateAndVerifyPolicyDocument(
			currDoc.Children[currScope],
			subTree,
			currScope,
			currDoc.Verbs,
			reqScopes,
			matchDocs,
		)
		if !ok {
			break
		}
	}
	if processedChildren != len(currDoc.Children) {
		return false, matchDocs
	}
	if _, ok := reqScopes[currScope]; ok && currDoc.Scope == currScope {
		matchDocs[currScope] = currDoc
	}
	return ok, matchDocs
}
populateAndVerifyPolicyDocument makes sure that the policy document is valid, and populates
the policy document with values based on the parent permissions. Since we only want to
iterate through the PolicyDocument once, we also search for a matching doc and return it.
See test cases for examples.
package policy
import (
	"github.com/porter-dev/porter/api/types"
)
func HasScopeAccess(
	policy []*types.PolicyDocument,
	reqScopes map[types.PermissionScope]*types.RequestAction,
) bool {
	for _, policyDoc := range policy {
		isValid, matchDocs := populateAndVerifyPolicyDocument(
			policyDoc,
			types.ScopeHeirarchy,
			types.ProjectScope,
			types.ReadWriteVerbGroup(),
			reqScopes,
			nil,
		)
		if !isValid {
			continue
		}
		for matchScope, matchDoc := range matchDocs {
			if len(matchDoc.Resources) > 0 && reqScopes[matchScope].Verb != types.APIVerbList {
				if !isResourceAllowed(matchDoc, reqScopes[matchScope].Resource) {
					isValid = false
				}
			}
			if !isVerbAllowed(matchDoc, reqScopes[matchScope].Verb) {
				isValid = false
			}
		}
		if isValid {
			return true
		}
	}
	return false
}
func isResourceAllowed(
	matchDoc *types.PolicyDocument,
	resource types.NameOrUInt,
) bool {
	valid := false
	for _, allowedResource := range matchDoc.Resources {
		if allowedResource == resource {
			valid = true
			break
		}
	}
	return valid
}
func isVerbAllowed(
	matchDoc *types.PolicyDocument,
	verb types.APIVerb,
) bool {
	valid := false
	for _, allowedVerb := range matchDoc.Verbs {
		if allowedVerb == verb {
			valid = true
		}
	}
	return valid
}