fix: use a client pointing at Docker's TUF by default (#104)

`policy.Options` now contains the arguments to `tuf.Client`'s constructor rather than an actual Client. If these arguments are not provided, defaults pointing at Docker's TUF repo will be used. An actual TUF client can be passed in on the context (which is useful for testing). If this is not provided `attest.Verify` will create a TUF client using the options on `policy.Options`.

---------

Co-authored-by: Joel Kamp <joel.kamp@docker.com>
This commit is contained in:
Jonny Stoten
2024-08-23 09:33:30 +01:00
committed by GitHub
parent 802725caf0
commit aed959f858
18 changed files with 227 additions and 84 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/tuf"
)
func resolveLocalPolicy(opts *Options, mapping *config.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
@@ -57,13 +58,13 @@ func resolveLocalPolicy(opts *Options, mapping *config.PolicyMapping, imageName
return policy, nil
}
func resolveTUFPolicy(opts *Options, mapping *config.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
func resolveTUFPolicy(opts *Options, tufClient tuf.Downloader, mapping *config.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
var URI string
var digest map[string]string
files := make([]*File, 0, len(mapping.Files))
for _, f := range mapping.Files {
filename := f.Path
file, err := opts.TUFClient.DownloadTarget(filename, filepath.Join(opts.LocalTargetsDir, filename))
file, err := tufClient.DownloadTarget(filename, filepath.Join(opts.LocalTargetsDir, filename))
if err != nil {
return nil, fmt.Errorf("failed to download policy file %s: %w", filename, err)
}
@@ -154,7 +155,7 @@ func findPolicyMatchImpl(imageName string, mappings *config.PolicyMappings, matc
return &policyMatch{matchType: matchTypeNoMatch, matchedName: imageName}, nil
}
func resolvePolicyByID(opts *Options) (*Policy, error) {
func resolvePolicyByID(opts *Options, tufClient tuf.Downloader) (*Policy, error) {
if opts.PolicyID != "" {
localMappings, err := config.LoadLocalMappings(opts.LocalPolicyDir)
if err != nil {
@@ -168,21 +169,21 @@ func resolvePolicyByID(opts *Options) (*Policy, error) {
}
// must check tuf
tufMappings, err := config.LoadTUFMappings(opts.TUFClient, opts.LocalTargetsDir)
tufMappings, err := config.LoadTUFMappings(tufClient, opts.LocalTargetsDir)
if err != nil {
return nil, fmt.Errorf("failed to load tuf policy mappings by id: %w", err)
}
policy := tufMappings.Policies[opts.PolicyID]
if policy != nil {
return resolveTUFPolicy(opts, policy, "", "")
return resolveTUFPolicy(opts, tufClient, policy, "", "")
}
return nil, fmt.Errorf("policy with id %s not found", opts.PolicyID)
}
return nil, nil
}
func ResolvePolicy(ctx context.Context, detailsResolver oci.ImageDetailsResolver, opts *Options) (*Policy, error) {
p, err := resolvePolicyByID(opts)
func ResolvePolicy(ctx context.Context, tufClient tuf.Downloader, detailsResolver oci.ImageDetailsResolver, opts *Options) (*Policy, error) {
p, err := resolvePolicyByID(opts, tufClient)
if err != nil {
return nil, fmt.Errorf("failed to resolve policy by id: %w", err)
}
@@ -209,7 +210,7 @@ func ResolvePolicy(ctx context.Context, detailsResolver oci.ImageDetailsResolver
return resolveLocalPolicy(opts, match.policy, imageName, match.matchedName)
}
// must check tuf
tufMappings, err := config.LoadTUFMappings(opts.TUFClient, opts.LocalTargetsDir)
tufMappings, err := config.LoadTUFMappings(tufClient, opts.LocalTargetsDir)
if err != nil {
return nil, fmt.Errorf("failed to load tuf policy mappings as fallback: %w", err)
}
@@ -218,7 +219,7 @@ func ResolvePolicy(ctx context.Context, detailsResolver oci.ImageDetailsResolver
if match.matchType == matchTypeMatchNoPolicy {
for _, mapping := range tufMappings.Policies {
if mapping.ID == match.rule.PolicyID {
return resolveTUFPolicy(opts, mapping, imageName, match.matchedName)
return resolveTUFPolicy(opts, tufClient, mapping, imageName, match.matchedName)
}
}
}
@@ -229,7 +230,7 @@ func ResolvePolicy(ctx context.Context, detailsResolver oci.ImageDetailsResolver
return nil, err
}
if match.matchType == matchTypePolicy {
return resolveTUFPolicy(opts, match.policy, imageName, match.matchedName)
return resolveTUFPolicy(opts, tufClient, match.policy, imageName, match.matchedName)
}
return nil, nil
}

View File

@@ -75,7 +75,6 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
tufClient := tuf.NewMockTufClient(tc.repo, test.CreateTempDir(t, "", "tuf-dest"))
if tc.policy == nil {
tc.policy = &policy.Options{
TUFClient: tufClient,
LocalTargetsDir: test.CreateTempDir(t, "", "tuf-targets"),
PolicyID: tc.policyID,
}
@@ -88,7 +87,7 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
require.NoError(t, err)
resolver, err := policy.CreateImageDetailsResolver(src)
require.NoError(t, err)
policy, err := policy.ResolvePolicy(ctx, resolver, tc.policy)
policy, err := policy.ResolvePolicy(ctx, tufClient, resolver, tc.policy)
if tc.resolveErrorStr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tc.resolveErrorStr)

View File

@@ -27,7 +27,7 @@ type Result struct {
}
type Options struct {
TUFClient tuf.Downloader
TUFClientOptions *tuf.ClientOptions
LocalTargetsDir string
LocalPolicyDir string
PolicyID string