gittuf/internal/policy/list.go
Aditya Sirish A Yelgundhalli 8c49dfea3a
policy, cmd: Add list-principals sub command
Signed-off-by: Aditya Sirish A Yelgundhalli <ayelgundhall@bloomberg.net>
2024-11-07 12:48:06 -05:00

104 lines
3 KiB
Go

// Copyright The gittuf Authors
// SPDX-License-Identifier: Apache-2.0
package policy
import (
"context"
"github.com/gittuf/gittuf/internal/gitinterface"
"github.com/gittuf/gittuf/internal/tuf"
)
type DelegationWithDepth struct {
Delegation tuf.Rule
Depth int
}
// ListRules returns a list of all the rules as an array of the delegations in a
// pre-order traversal of the delegation tree, with the depth of each
// delegation.
func ListRules(ctx context.Context, repo *gitinterface.Repository, targetRef string) ([]*DelegationWithDepth, error) {
state, err := LoadCurrentState(ctx, repo, targetRef)
if err != nil {
return nil, err
}
if !state.HasTargetsRole(TargetsRoleName) {
return nil, nil
}
topLevelTargetsMetadata, err := state.GetTargetsMetadata(TargetsRoleName, true)
if err != nil {
return nil, err
}
delegationsToSearch := []*DelegationWithDepth{}
allDelegations := []*DelegationWithDepth{}
for _, topLevelDelegation := range topLevelTargetsMetadata.GetRules() {
if topLevelDelegation.ID() == tuf.AllowRuleName {
continue
}
delegationsToSearch = append(delegationsToSearch, &DelegationWithDepth{Delegation: topLevelDelegation, Depth: 0})
}
seenRoles := map[string]bool{TargetsRoleName: true}
for len(delegationsToSearch) > 0 {
currentDelegation := delegationsToSearch[0]
delegationsToSearch = delegationsToSearch[1:]
// allDelegations will be the returned list of all the delegations in pre-order traversal, no delegations will be popped off
allDelegations = append(allDelegations, currentDelegation)
if _, seen := seenRoles[currentDelegation.Delegation.ID()]; seen {
continue
}
if state.HasTargetsRole(currentDelegation.Delegation.ID()) {
currentMetadata, err := state.GetTargetsMetadata(currentDelegation.Delegation.ID(), true)
if err != nil {
return nil, err
}
seenRoles[currentDelegation.Delegation.ID()] = true
// We construct localDelegations first so that we preserve the order
// of delegations in currentMetadata in delegationsToSearch
localDelegations := []*DelegationWithDepth{}
for _, delegation := range currentMetadata.GetRules() {
if delegation.ID() == tuf.AllowRuleName {
continue
}
localDelegations = append(localDelegations, &DelegationWithDepth{Delegation: delegation, Depth: currentDelegation.Depth + 1})
}
if len(localDelegations) > 0 {
delegationsToSearch = append(localDelegations, delegationsToSearch...)
}
}
}
return allDelegations, nil
}
// ListPrincipals returns the principals present in the specified rule file.
// `targetRef` can be used to control which policy reference is used.
func ListPrincipals(ctx context.Context, repo *gitinterface.Repository, targetRef, policyName string) (map[string]tuf.Principal, error) {
state, err := LoadCurrentState(ctx, repo, targetRef)
if err != nil {
return nil, err
}
if !state.HasTargetsRole(policyName) {
return nil, ErrPolicyNotFound
}
metadata, err := state.GetTargetsMetadata(policyName, false)
if err != nil {
return nil, err
}
return metadata.GetPrincipals(), nil
}