blob: 2e0c42b65c0444e6fa0402b9ef42e2eec00834a8 [file] [log] [blame]
package targets
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/theupdateframework/go-tuf/data"
"github.com/theupdateframework/go-tuf/verify"
)
var (
defaultPathPatterns = []string{"tmp", "*"}
noMatchPathPatterns = []string{"vars", "null"}
)
func TestDelegationsIterator(t *testing.T) {
topTargetsPubKey := &data.PublicKey{
Type: data.KeyTypeEd25519,
Scheme: data.KeySchemeEd25519,
Algorithms: data.HashAlgorithms,
Value: []byte(`{"public":"aaaaec567e5901ba3976c34f7cd5169704292439bf71e6aa19c64b96706f95ef"}`),
}
delTargetsPubKey := &data.PublicKey{
Type: data.KeyTypeEd25519,
Scheme: data.KeySchemeEd25519,
Algorithms: data.HashAlgorithms,
Value: []byte(`{"public":"bbbbec567e5901ba3976c34f7cd5169704292439bf71e6aa19c64b96706f95ef"}`),
}
defaultKeyIDs := delTargetsPubKey.IDs()
var iteratorTests = []struct {
testName string
roles map[string][]data.DelegatedRole
file string
resultOrder []string
err error
}{
{
testName: "no delegation",
roles: map[string][]data.DelegatedRole{
"targets": {},
},
file: "test.txt",
resultOrder: []string{"targets"},
},
{
testName: "no termination",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"b": {
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"c": {
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"e": {
{Name: "f", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "g", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"g": {
{Name: "h", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "i", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "j", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "",
resultOrder: []string{"targets", "b", "c", "d", "e", "f", "g", "h", "i", "j"},
},
{
testName: "terminated in b",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs, Terminating: true},
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"b": {
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "",
resultOrder: []string{"targets", "b", "c", "d"},
},
{
testName: "path does not match b",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "b", Paths: noMatchPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"b": {
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "",
resultOrder: []string{"targets", "e"},
},
{
testName: "path does not match b - path prefixes",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "b", PathHashPrefixes: []string{"33472a4909"}, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "c", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633"}, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"c": {
{Name: "d", PathHashPrefixes: []string{"8baf"}, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "e", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633472a49096ed87f8f764bd597831eac371f40ac39"}, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "/e/f/g.txt",
resultOrder: []string{"targets", "c", "e"},
},
{
testName: "err paths and pathHashPrefixes are set",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "b", Paths: defaultPathPatterns, PathHashPrefixes: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"b": {},
},
file: "",
resultOrder: []string{"targets"},
err: data.ErrPathsAndPathHashesSet,
},
{
testName: "cycle avoided 1",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"a": {
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"b": {
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "",
resultOrder: []string{"targets", "a", "b", "d", "e"},
},
{
testName: "cycle avoided 2",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"a": {
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"b": {
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"c": {
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "",
resultOrder: []string{"targets", "a", "b", "c"},
},
{
testName: "diamond delegation",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"b": {
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"c": {
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "",
resultOrder: []string{"targets", "b", "d", "c"},
},
{
testName: "simple cycle",
roles: map[string][]data.DelegatedRole{
"targets": {
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
"a": {
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
},
},
file: "",
resultOrder: []string{"targets", "a"},
},
}
for _, tt := range iteratorTests {
t.Run(tt.testName, func(t *testing.T) {
topLevelDB := verify.NewDB()
topLevelDB.AddKey(topTargetsPubKey.IDs()[0], topTargetsPubKey)
topLevelDB.AddRole("targets", &data.Role{
KeyIDs: topTargetsPubKey.IDs(),
Threshold: 1,
})
d, err := NewDelegationsIterator(tt.file, topLevelDB)
assert.NoError(t, err)
var iterationOrder []string
for {
r, ok := d.Next()
if !ok {
break
}
// A delegation should have associated keys. Testing the exact keys
// isn't useful in this module since the keys are supplied by the
// caller in the arguments to Add().
assert.Greater(t, len(r.Delegatee.KeyIDs), 0)
iterationOrder = append(iterationOrder, r.Delegatee.Name)
delegations, ok := tt.roles[r.Delegatee.Name]
if !ok {
continue
}
db, err := verify.NewDBFromDelegations(&data.Delegations{
Roles: delegations,
})
assert.NoError(t, err)
err = d.Add(delegations, r.Delegatee.Name, db)
assert.Equal(t, tt.err, err)
}
assert.Equal(t, tt.resultOrder, iterationOrder)
})
}
}
func TestNewDelegationsIteratorError(t *testing.T) {
// Empty DB. It is supposed to have at least the top-level targets role and
// keys.
tldb := verify.NewDB()
_, err := NewDelegationsIterator("targets", tldb)
assert.ErrorIs(t, err, ErrTopLevelTargetsRoleMissing)
}