Add platform filtering support to mapping.yml (#167)
* chore!: rename package config -> mapping * feat: add platform filtering support to mapping.yml
This commit is contained in:
@@ -203,8 +203,14 @@ rules:
|
||||
- pattern: "^docker[.]io/library/(.*)$"
|
||||
policy-id: docker-official-images
|
||||
- pattern: "^public[.]ecr[.]aws/docker/library/(.*)$"
|
||||
platforms: ["linux/amd64"] # optional: restrict image platforms for matching policies (default: all)
|
||||
rewrite: docker.io/library/$1
|
||||
```
|
||||
`platforms` in the second rule above is optional and can be used to restrict the platforms for which the policy
|
||||
is evaluated. If the `platforms` field is not present, the policy will be applied to all platforms.
|
||||
It's important to note that the `platforms` field is a filter, and is applied before the `pattern`
|
||||
field is processed, so both `platforms` and `pattern` need to match in order for the policy to be selected
|
||||
(or the rewrite to be processed if present).
|
||||
|
||||
As before, any repository in the `docker.io/library` namespace will be evaluated against the policy in `doi/policy.rego`.
|
||||
The second rule will rewrite any repository in the `public.ecr.aws/docker/library` namespace to `docker.io/library`.
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
|
||||
"github.com/docker/attest"
|
||||
"github.com/docker/attest/attestation"
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/docker/attest/internal/test"
|
||||
"github.com/docker/attest/mapping"
|
||||
"github.com/docker/attest/oci"
|
||||
"github.com/docker/attest/policy"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
@@ -39,7 +39,7 @@ func TestAttestationReferenceTypes(t *testing.T) {
|
||||
referrersServer *httptest.Server
|
||||
useDigest bool
|
||||
referrersRepo string
|
||||
attestationSource config.AttestationStyle
|
||||
attestationSource mapping.AttestationStyle
|
||||
expectFailure bool
|
||||
}{
|
||||
{
|
||||
@@ -55,26 +55,26 @@ func TestAttestationReferenceTypes(t *testing.T) {
|
||||
name: "attached attestations, referrers repo (mismatched args)",
|
||||
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
|
||||
expectFailure: true, // mismatched args
|
||||
attestationSource: config.AttestationStyleAttached,
|
||||
attestationSource: mapping.AttestationStyleAttached,
|
||||
referrersRepo: "referrers",
|
||||
},
|
||||
{
|
||||
name: "referrers attestations, referrers repo (no policy)",
|
||||
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
|
||||
expectFailure: true, // no policy
|
||||
attestationSource: config.AttestationStyleReferrers,
|
||||
attestationSource: mapping.AttestationStyleReferrers,
|
||||
referrersRepo: "referrers",
|
||||
},
|
||||
{
|
||||
name: "referrers attestations",
|
||||
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
|
||||
attestationSource: config.AttestationStyleReferrers,
|
||||
attestationSource: mapping.AttestationStyleReferrers,
|
||||
},
|
||||
{
|
||||
name: "referrers attestations, no referrers support on server",
|
||||
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(false)),
|
||||
|
||||
attestationSource: config.AttestationStyleReferrers,
|
||||
attestationSource: mapping.AttestationStyleReferrers,
|
||||
referrersServer: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
|
||||
},
|
||||
} {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package config
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"regexp"
|
||||
|
||||
"github.com/docker/attest/tuf"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@@ -33,6 +34,13 @@ func validateMappingsFile(mappings *policyMappingsFile) error {
|
||||
if rule.PolicyID != "" && rule.Replacement != "" {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("rule cannot have both policy-id and replacement: %s", rule))
|
||||
}
|
||||
if rule.Platforms != nil {
|
||||
for _, platform := range rule.Platforms {
|
||||
if platform == "" {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("rule has empty platform: %s", rule))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, policy := range mappings.Policies {
|
||||
if policy.ID == "" {
|
||||
@@ -100,14 +108,24 @@ func expandMappingFile(mappingFile *policyMappingsFile) (*PolicyMappings, error)
|
||||
|
||||
var rules []*PolicyRule
|
||||
for _, rule := range mappingFile.Rules {
|
||||
r, err := regexp.Compile(rule.Pattern)
|
||||
patternRegex, err := regexp.Compile(rule.Pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
platforms := make([]*v1.Platform, 0, len(rule.Platforms))
|
||||
for _, platform := range rule.Platforms {
|
||||
parsedPlatform, err := v1.ParsePlatform(platform)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse platform %s: %w", platform, err)
|
||||
}
|
||||
platforms = append(platforms, parsedPlatform)
|
||||
}
|
||||
|
||||
rules = append(rules, &PolicyRule{
|
||||
Pattern: r,
|
||||
Pattern: patternRegex,
|
||||
PolicyID: rule.PolicyID,
|
||||
Replacement: rule.Replacement,
|
||||
Platforms: platforms,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package config
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"testing"
|
||||
80
mapping/match.go
Normal file
80
mapping/match.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
)
|
||||
|
||||
type matchType string
|
||||
|
||||
const (
|
||||
MatchTypePolicy matchType = "policy"
|
||||
MatchTypeMatchNoPolicy matchType = "match_no_policy"
|
||||
MatchTypeNoMatch matchType = "no_match"
|
||||
)
|
||||
|
||||
type PolicyMatch struct {
|
||||
MatchType matchType
|
||||
Policy *PolicyMapping
|
||||
Rule *PolicyRule
|
||||
MatchedName string
|
||||
}
|
||||
|
||||
func (mappings *PolicyMappings) FindPolicyMatch(imageName string, platform *v1.Platform) (*PolicyMatch, error) {
|
||||
if mappings == nil {
|
||||
return &PolicyMatch{MatchType: MatchTypeNoMatch, MatchedName: imageName}, nil
|
||||
}
|
||||
return mappings.findPolicyMatchImpl(imageName, platform, make(map[*PolicyRule]bool))
|
||||
}
|
||||
|
||||
func (mappings *PolicyMappings) findPolicyMatchImpl(imageName string, platform *v1.Platform, matched map[*PolicyRule]bool) (*PolicyMatch, error) {
|
||||
for _, rule := range mappings.Rules {
|
||||
if !rule.matchesPlatform(platform) {
|
||||
continue
|
||||
}
|
||||
if rule.Pattern.MatchString(imageName) {
|
||||
switch {
|
||||
case rule.PolicyID == "" && rule.Replacement == "":
|
||||
return nil, fmt.Errorf("rule %s has neither policy-id nor rewrite", rule.Pattern)
|
||||
case rule.PolicyID != "" && rule.Replacement != "":
|
||||
return nil, fmt.Errorf("rule %s has both policy-id and rewrite", rule.Pattern)
|
||||
case rule.PolicyID != "":
|
||||
policy := mappings.Policies[rule.PolicyID]
|
||||
if policy != nil {
|
||||
return &PolicyMatch{
|
||||
MatchType: MatchTypePolicy,
|
||||
Policy: policy,
|
||||
Rule: rule,
|
||||
MatchedName: imageName,
|
||||
}, nil
|
||||
}
|
||||
return &PolicyMatch{
|
||||
MatchType: MatchTypeMatchNoPolicy,
|
||||
Rule: rule,
|
||||
MatchedName: imageName,
|
||||
}, nil
|
||||
case rule.Replacement != "":
|
||||
if matched[rule] {
|
||||
return nil, fmt.Errorf("rewrite loop detected")
|
||||
}
|
||||
matched[rule] = true
|
||||
imageName = rule.Pattern.ReplaceAllString(imageName, rule.Replacement)
|
||||
return mappings.findPolicyMatchImpl(imageName, platform, matched)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &PolicyMatch{MatchType: MatchTypeNoMatch}, nil
|
||||
}
|
||||
|
||||
func (rule *PolicyRule) matchesPlatform(platform *v1.Platform) bool {
|
||||
if len(rule.Platforms) == 0 {
|
||||
return true
|
||||
}
|
||||
for i := range rule.Platforms {
|
||||
if rule.Platforms[i].Equals(*platform) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
200
mapping/match_test.go
Normal file
200
mapping/match_test.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFindPolicyMatch(t *testing.T) {
|
||||
defaultPlatform, err := v1.ParsePlatform("linux/amd64")
|
||||
require.NoError(t, err)
|
||||
testCases := []struct {
|
||||
name string
|
||||
imageName string
|
||||
mappingDir string
|
||||
expectError bool
|
||||
expectLoadingError bool
|
||||
expectedMatchType matchType
|
||||
expectedPolicyID string
|
||||
expectedImageName string
|
||||
platform string
|
||||
}{
|
||||
{
|
||||
name: "alpine",
|
||||
mappingDir: "doi",
|
||||
imageName: "docker.io/library/alpine",
|
||||
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "no match",
|
||||
mappingDir: "doi",
|
||||
imageName: "docker.io/something/else",
|
||||
|
||||
expectedMatchType: MatchTypeNoMatch,
|
||||
},
|
||||
{
|
||||
name: "match, no policy",
|
||||
mappingDir: "local",
|
||||
imageName: "docker.io/library/alpine",
|
||||
|
||||
expectedMatchType: MatchTypeMatchNoPolicy,
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "simple rewrite",
|
||||
mappingDir: "simple-rewrite",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "rewrite no match",
|
||||
mappingDir: "rewrite-to-no-match",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: MatchTypeNoMatch,
|
||||
},
|
||||
{
|
||||
name: "rewrite to match, no policy",
|
||||
mappingDir: "rewrite-to-local",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: MatchTypeMatchNoPolicy,
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "multiple rewrites",
|
||||
mappingDir: "rewrite-multiple",
|
||||
imageName: "myevencoolermirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "rewrite loop",
|
||||
mappingDir: "rewrite-loop",
|
||||
imageName: "yin/alpine",
|
||||
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "alpine with platform",
|
||||
mappingDir: "doi",
|
||||
imageName: "docker.io/library/alpine",
|
||||
platform: "linux/amd64",
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "alpine with platform",
|
||||
mappingDir: "doi-platform",
|
||||
imageName: "docker.io/library/alpine",
|
||||
platform: "linux/amd64",
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "alpine with no matching platform",
|
||||
mappingDir: "doi-platform",
|
||||
imageName: "docker.io/library/alpine",
|
||||
platform: "linux/arm64",
|
||||
expectedMatchType: MatchTypeNoMatch,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
},
|
||||
{
|
||||
name: "alpine with platform",
|
||||
mappingDir: "doi-platform",
|
||||
imageName: "docker.io/library/alpine",
|
||||
platform: "linux/amd64",
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "alpine with invalid platform in mapping",
|
||||
mappingDir: "doi-platform-broken",
|
||||
imageName: "docker.io/library/alpine",
|
||||
platform: "linux/amd64",
|
||||
expectLoadingError: true,
|
||||
},
|
||||
{
|
||||
name: "firefox with > 1 platforms in policy",
|
||||
mappingDir: "doi-platform",
|
||||
imageName: "docker.io/mozilla/firefox",
|
||||
platform: "linux/arm64",
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/mozilla/firefox",
|
||||
},
|
||||
{
|
||||
name: "firefox with > 1 platforms in policy (no match)",
|
||||
mappingDir: "doi-platform",
|
||||
imageName: "docker.io/mozilla/firefox",
|
||||
platform: "macOs/arm64",
|
||||
expectedMatchType: MatchTypeNoMatch,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
},
|
||||
{
|
||||
name: "rewrite and platform",
|
||||
mappingDir: "doi-platform",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
platform: "linux/amd64",
|
||||
expectedMatchType: MatchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "rewrite and platform mismatch",
|
||||
mappingDir: "doi-platform",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
platform: "macOs/amd64",
|
||||
expectedMatchType: MatchTypeNoMatch,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mappings, err := LoadLocalMappings(filepath.Join("testdata", "mappings", tc.mappingDir))
|
||||
if tc.expectLoadingError {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
platform := defaultPlatform
|
||||
if tc.platform != "" {
|
||||
platform, err = v1.ParsePlatform(tc.platform)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
match, err := mappings.FindPolicyMatch(tc.imageName, platform)
|
||||
if tc.expectError {
|
||||
require.Error(t, err)
|
||||
// TODO: check error matches expected error message
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedMatchType, match.MatchType)
|
||||
if match.MatchType == MatchTypePolicy {
|
||||
if assert.NotNil(t, match.Policy) {
|
||||
assert.Equal(t, tc.expectedPolicyID, match.Policy.ID)
|
||||
}
|
||||
}
|
||||
if match.MatchType == MatchTypeMatchNoPolicy || match.MatchType == MatchTypePolicy {
|
||||
assert.Equal(t, tc.expectedImageName, match.MatchedName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
11
mapping/testdata/mappings/doi-platform-broken/mapping.yaml
vendored
Normal file
11
mapping/testdata/mappings/doi-platform-broken/mapping.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: v1
|
||||
kind: policy-mapping
|
||||
policies:
|
||||
- id: docker-official-images
|
||||
description: Docker Official Images
|
||||
files:
|
||||
- path: doi/policy.rego
|
||||
rules:
|
||||
- pattern: "^docker[.]io/library/(.*)$"
|
||||
platforms: ["linux/amd64/broken/platform/spec/1.0:foobar"]
|
||||
policy-id: docker-official-images
|
||||
17
mapping/testdata/mappings/doi-platform/mapping.yaml
vendored
Normal file
17
mapping/testdata/mappings/doi-platform/mapping.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
version: v1
|
||||
kind: policy-mapping
|
||||
policies:
|
||||
- id: docker-official-images
|
||||
description: Docker Official Images
|
||||
files:
|
||||
- path: doi/policy.rego
|
||||
rules:
|
||||
- pattern: "^docker[.]io/library/(.*)$"
|
||||
platforms: ["linux/amd64"]
|
||||
policy-id: docker-official-images
|
||||
- pattern: "^docker.io/mozilla/(.*)$"
|
||||
platforms: ["linux/amd64", "linux/arm64"]
|
||||
policy-id: docker-official-images
|
||||
- pattern: "^mycoolmirror[.]org/library/(.*)$"
|
||||
platforms: ["linux/amd64"]
|
||||
rewrite: "docker.io/library/$1"
|
||||
@@ -1,7 +1,9 @@
|
||||
package config
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
)
|
||||
|
||||
type policyMappingsFile struct {
|
||||
@@ -12,9 +14,10 @@ type policyMappingsFile struct {
|
||||
}
|
||||
|
||||
type policyRuleFile struct {
|
||||
Pattern string `json:"pattern"`
|
||||
PolicyID string `json:"policy-id"`
|
||||
Replacement string `json:"rewrite"`
|
||||
Pattern string `json:"pattern"`
|
||||
Platforms []string `json:"platforms"`
|
||||
PolicyID string `json:"policy-id"`
|
||||
Replacement string `json:"rewrite"`
|
||||
}
|
||||
|
||||
type PolicyMappings struct {
|
||||
@@ -51,4 +54,5 @@ type PolicyRule struct {
|
||||
Pattern *regexp.Regexp
|
||||
PolicyID string
|
||||
Replacement string
|
||||
Platforms []*v1.Platform
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/attest/config"
|
||||
)
|
||||
|
||||
type matchType string
|
||||
|
||||
const (
|
||||
matchTypePolicy matchType = "policy"
|
||||
matchTypeMatchNoPolicy matchType = "match_no_policy"
|
||||
matchTypeNoMatch matchType = "no_match"
|
||||
)
|
||||
|
||||
type policyMatch struct {
|
||||
matchType matchType
|
||||
policy *config.PolicyMapping
|
||||
rule *config.PolicyRule
|
||||
matchedName string
|
||||
}
|
||||
|
||||
func findPolicyMatch(imageName string, mappings *config.PolicyMappings) (*policyMatch, error) {
|
||||
if mappings == nil {
|
||||
return &policyMatch{matchType: matchTypeNoMatch, matchedName: imageName}, nil
|
||||
}
|
||||
return findPolicyMatchImpl(imageName, mappings, make(map[*config.PolicyRule]bool))
|
||||
}
|
||||
|
||||
func findPolicyMatchImpl(imageName string, mappings *config.PolicyMappings, matched map[*config.PolicyRule]bool) (*policyMatch, error) {
|
||||
for _, rule := range mappings.Rules {
|
||||
if rule.Pattern.MatchString(imageName) {
|
||||
switch {
|
||||
case rule.PolicyID == "" && rule.Replacement == "":
|
||||
return nil, fmt.Errorf("rule %s has neither policy-id nor rewrite", rule.Pattern)
|
||||
case rule.PolicyID != "" && rule.Replacement != "":
|
||||
return nil, fmt.Errorf("rule %s has both policy-id and rewrite", rule.Pattern)
|
||||
case rule.PolicyID != "":
|
||||
policy := mappings.Policies[rule.PolicyID]
|
||||
if policy != nil {
|
||||
return &policyMatch{
|
||||
matchType: matchTypePolicy,
|
||||
policy: policy,
|
||||
rule: rule,
|
||||
matchedName: imageName,
|
||||
}, nil
|
||||
}
|
||||
return &policyMatch{
|
||||
matchType: matchTypeMatchNoPolicy,
|
||||
rule: rule,
|
||||
matchedName: imageName,
|
||||
}, nil
|
||||
case rule.Replacement != "":
|
||||
if matched[rule] {
|
||||
return nil, fmt.Errorf("rewrite loop detected")
|
||||
}
|
||||
matched[rule] = true
|
||||
imageName = rule.Pattern.ReplaceAllString(imageName, rule.Replacement)
|
||||
return findPolicyMatchImpl(imageName, mappings, matched)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &policyMatch{matchType: matchTypeNoMatch, matchedName: imageName}, nil
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFindPolicyMatch(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
imageName string
|
||||
mappingDir string
|
||||
|
||||
expectError bool
|
||||
expectLoadingError bool
|
||||
expectedMatchType matchType
|
||||
expectedPolicyID string
|
||||
expectedImageName string
|
||||
}{
|
||||
{
|
||||
name: "alpine",
|
||||
mappingDir: "doi",
|
||||
imageName: "docker.io/library/alpine",
|
||||
|
||||
expectedMatchType: matchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "no match",
|
||||
mappingDir: "doi",
|
||||
imageName: "docker.io/something/else",
|
||||
|
||||
expectedMatchType: matchTypeNoMatch,
|
||||
expectedImageName: "docker.io/something/else",
|
||||
},
|
||||
{
|
||||
name: "match, no policy",
|
||||
mappingDir: "local",
|
||||
imageName: "docker.io/library/alpine",
|
||||
|
||||
expectedMatchType: matchTypeMatchNoPolicy,
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "simple rewrite",
|
||||
mappingDir: "simple-rewrite",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: matchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "rewrite no match",
|
||||
mappingDir: "rewrite-to-no-match",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: matchTypeNoMatch,
|
||||
expectedImageName: "badredirect.org/alpine",
|
||||
},
|
||||
{
|
||||
name: "rewrite to match, no policy",
|
||||
mappingDir: "rewrite-to-local",
|
||||
imageName: "mycoolmirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: matchTypeMatchNoPolicy,
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "multiple rewrites",
|
||||
mappingDir: "rewrite-multiple",
|
||||
imageName: "myevencoolermirror.org/library/alpine",
|
||||
|
||||
expectedMatchType: matchTypePolicy,
|
||||
expectedPolicyID: "docker-official-images",
|
||||
expectedImageName: "docker.io/library/alpine",
|
||||
},
|
||||
{
|
||||
name: "rewrite loop",
|
||||
mappingDir: "rewrite-loop",
|
||||
imageName: "yin/alpine",
|
||||
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mappings, err := config.LoadLocalMappings(filepath.Join("testdata", "mappings", tc.mappingDir))
|
||||
require.NoError(t, err)
|
||||
match, err := findPolicyMatch(tc.imageName, mappings)
|
||||
if tc.expectError {
|
||||
require.Error(t, err)
|
||||
// TODO: check error matches expected error message
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedMatchType, match.matchType)
|
||||
if match.matchType == matchTypePolicy {
|
||||
if assert.NotNil(t, match.policy) {
|
||||
assert.Equal(t, tc.expectedPolicyID, match.policy.ID)
|
||||
}
|
||||
}
|
||||
assert.Equal(t, tc.expectedImageName, match.matchedName)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/attest/attestation"
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/docker/attest/mapping"
|
||||
"github.com/docker/attest/oci"
|
||||
intoto "github.com/in-toto/in-toto-golang/in_toto"
|
||||
"github.com/package-url/packageurl-go"
|
||||
@@ -22,9 +22,9 @@ func CreateImageDetailsResolver(imageSource *oci.ImageSpec) (oci.ImageDetailsRes
|
||||
return nil, fmt.Errorf("unsupported image source type: %s", imageSource.Type)
|
||||
}
|
||||
|
||||
func CreateAttestationResolver(resolver oci.ImageDetailsResolver, mapping *config.PolicyMapping) (attestation.Resolver, error) {
|
||||
if mapping.Attestations != nil {
|
||||
if mapping.Attestations.Style == config.AttestationStyleAttached {
|
||||
func CreateAttestationResolver(resolver oci.ImageDetailsResolver, policyMapping *mapping.PolicyMapping) (attestation.Resolver, error) {
|
||||
if policyMapping.Attestations != nil {
|
||||
if policyMapping.Attestations.Style == mapping.AttestationStyleAttached {
|
||||
switch resolver := resolver.(type) {
|
||||
case *oci.RegistryImageDetailsResolver:
|
||||
return attestation.NewRegistryResolver(resolver)
|
||||
@@ -34,8 +34,8 @@ func CreateAttestationResolver(resolver oci.ImageDetailsResolver, mapping *confi
|
||||
return nil, fmt.Errorf("unsupported image details resolver type: %T", resolver)
|
||||
}
|
||||
}
|
||||
if mapping.Attestations.Repo != "" {
|
||||
return attestation.NewReferrersResolver(resolver, attestation.WithReferrersRepo(mapping.Attestations.Repo))
|
||||
if policyMapping.Attestations.Repo != "" {
|
||||
return attestation.NewReferrersResolver(resolver, attestation.WithReferrersRepo(policyMapping.Attestations.Repo))
|
||||
}
|
||||
}
|
||||
return attestation.NewReferrersResolver(resolver)
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/attest/attestation"
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/docker/attest/internal/test"
|
||||
"github.com/docker/attest/mapping"
|
||||
"github.com/docker/attest/oci"
|
||||
"github.com/docker/attest/policy"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
@@ -45,7 +45,8 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
|
||||
defaultResolver := attestation.MockResolver{
|
||||
Envs: []*attestation.Envelope{loadAttestation(t, ExampleAttestation)},
|
||||
}
|
||||
|
||||
defaultPlatform, err := v1.ParsePlatform("linux/amd64")
|
||||
require.NoError(t, err)
|
||||
testCases := []struct {
|
||||
policyPath string
|
||||
expectSuccess bool
|
||||
@@ -87,7 +88,7 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
|
||||
imageName, err := tc.resolver.ImageName(ctx)
|
||||
require.NoError(t, err)
|
||||
resolver := policy.NewResolver(nil, tc.opts)
|
||||
policy, err := resolver.ResolvePolicy(ctx, imageName)
|
||||
policy, err := resolver.ResolvePolicy(ctx, imageName, defaultPlatform)
|
||||
if tc.resolveErrorStr != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tc.resolveErrorStr)
|
||||
@@ -108,7 +109,7 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadingMappings(t *testing.T) {
|
||||
policyMappings, err := config.LoadLocalMappings(filepath.Join("testdata", "policies", "allow"))
|
||||
policyMappings, err := mapping.LoadLocalMappings(filepath.Join("testdata", "policies", "allow"))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(policyMappings.Rules), 3)
|
||||
for _, mirror := range policyMappings.Rules {
|
||||
@@ -125,32 +126,32 @@ func TestCreateAttestationResolver(t *testing.T) {
|
||||
layoutResolver := &attestation.LayoutResolver{}
|
||||
registryResolver := &oci.RegistryImageDetailsResolver{}
|
||||
|
||||
nilRepoReferrers := &config.PolicyMapping{
|
||||
Attestations: &config.AttestationConfig{
|
||||
Style: config.AttestationStyleReferrers,
|
||||
nilRepoReferrers := &mapping.PolicyMapping{
|
||||
Attestations: &mapping.AttestationConfig{
|
||||
Style: mapping.AttestationStyleReferrers,
|
||||
},
|
||||
}
|
||||
referrers := &config.PolicyMapping{
|
||||
Attestations: &config.AttestationConfig{
|
||||
referrers := &mapping.PolicyMapping{
|
||||
Attestations: &mapping.AttestationConfig{
|
||||
Repo: "localhost:5000/repo",
|
||||
Style: config.AttestationStyleReferrers,
|
||||
Style: mapping.AttestationStyleReferrers,
|
||||
},
|
||||
}
|
||||
attached := &config.PolicyMapping{
|
||||
Attestations: &config.AttestationConfig{
|
||||
Style: config.AttestationStyleAttached,
|
||||
attached := &mapping.PolicyMapping{
|
||||
Attestations: &mapping.AttestationConfig{
|
||||
Style: mapping.AttestationStyleAttached,
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
resolver oci.ImageDetailsResolver
|
||||
mapping *config.PolicyMapping
|
||||
mapping *mapping.PolicyMapping
|
||||
errorStr string
|
||||
}{
|
||||
{name: "referrers", resolver: layoutResolver, mapping: referrers},
|
||||
{name: "referrers (no mapped repo)", resolver: layoutResolver, mapping: nilRepoReferrers},
|
||||
{name: "referrers (no mapping)", resolver: layoutResolver, mapping: &config.PolicyMapping{Attestations: nil}},
|
||||
{name: "referrers (no mapping)", resolver: layoutResolver, mapping: &mapping.PolicyMapping{Attestations: nil}},
|
||||
{name: "attached (registry)", resolver: registryResolver, mapping: attached},
|
||||
{name: "attached (layout)", resolver: layoutResolver, mapping: attached},
|
||||
{name: "attached (unsupported)", resolver: mockResolver, mapping: attached, errorStr: "unsupported image details resolver type"},
|
||||
@@ -169,11 +170,11 @@ func TestCreateAttestationResolver(t *testing.T) {
|
||||
}
|
||||
switch resolver.(type) {
|
||||
case *attestation.ReferrersResolver:
|
||||
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleReferrers)
|
||||
assert.Equal(t, tc.mapping.Attestations.Style, mapping.AttestationStyleReferrers)
|
||||
case *attestation.RegistryResolver:
|
||||
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleAttached)
|
||||
assert.Equal(t, tc.mapping.Attestations.Style, mapping.AttestationStyleAttached)
|
||||
case *attestation.LayoutResolver:
|
||||
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleAttached)
|
||||
assert.Equal(t, tc.mapping.Attestations.Style, mapping.AttestationStyleAttached)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/docker/attest/internal/util"
|
||||
"github.com/docker/attest/mapping"
|
||||
"github.com/docker/attest/tuf"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
)
|
||||
|
||||
type Resolver struct {
|
||||
@@ -25,7 +26,7 @@ func NewResolver(tufClient tuf.Downloader, opts *Options) *Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Resolver) ResolvePolicy(_ context.Context, imageName string) (*Policy, error) {
|
||||
func (r *Resolver) ResolvePolicy(_ context.Context, imageName string, platform *v1.Platform) (*Policy, error) {
|
||||
p, err := r.resolvePolicyByID()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve policy by id: %w", err)
|
||||
@@ -37,45 +38,45 @@ func (r *Resolver) ResolvePolicy(_ context.Context, imageName string) (*Policy,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse image name: %w", err)
|
||||
}
|
||||
localMappings, err := config.LoadLocalMappings(r.opts.LocalPolicyDir)
|
||||
localMappings, err := mapping.LoadLocalMappings(r.opts.LocalPolicyDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load local policy mappings: %w", err)
|
||||
}
|
||||
match, err := findPolicyMatch(imageName, localMappings)
|
||||
match, err := localMappings.FindPolicyMatch(imageName, platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if match.matchType == matchTypePolicy {
|
||||
return r.resolveLocalPolicy(match.policy, imageName, match.matchedName)
|
||||
if match.MatchType == mapping.MatchTypePolicy {
|
||||
return r.resolveLocalPolicy(match.Policy, imageName, match.MatchedName)
|
||||
}
|
||||
if !r.opts.DisableTUF {
|
||||
tufMappings, err := config.LoadTUFMappings(r.tufClient, r.opts.LocalTargetsDir)
|
||||
tufMappings, err := mapping.LoadTUFMappings(r.tufClient, r.opts.LocalTargetsDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load tuf policy mappings as fallback: %w", err)
|
||||
}
|
||||
|
||||
// it's a mirror of a tuf policy
|
||||
if match.matchType == matchTypeMatchNoPolicy {
|
||||
if match.MatchType == mapping.MatchTypeMatchNoPolicy {
|
||||
for _, mapping := range tufMappings.Policies {
|
||||
if mapping.ID == match.rule.PolicyID {
|
||||
return r.resolveTUFPolicy(mapping, imageName, match.matchedName)
|
||||
if mapping.ID == match.Rule.PolicyID {
|
||||
return r.resolveTUFPolicy(mapping, imageName, match.MatchedName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try to resolve a tuf policy directly
|
||||
match, err = findPolicyMatch(imageName, tufMappings)
|
||||
match, err = tufMappings.FindPolicyMatch(imageName, platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if match.matchType == matchTypePolicy {
|
||||
return r.resolveTUFPolicy(match.policy, imageName, match.matchedName)
|
||||
if match.MatchType == mapping.MatchTypePolicy {
|
||||
return r.resolveTUFPolicy(match.Policy, imageName, match.MatchedName)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *Resolver) resolveLocalPolicy(mapping *config.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
|
||||
func (r *Resolver) resolveLocalPolicy(mapping *mapping.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
|
||||
if r.opts.LocalPolicyDir == "" {
|
||||
return nil, fmt.Errorf("local policy dir not set")
|
||||
}
|
||||
@@ -118,7 +119,7 @@ func (r *Resolver) resolveLocalPolicy(mapping *config.PolicyMapping, imageName s
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func (r *Resolver) resolveTUFPolicy(mapping *config.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
|
||||
func (r *Resolver) resolveTUFPolicy(mapping *mapping.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
|
||||
var URI string
|
||||
var digest map[string]string
|
||||
files := make([]*File, 0, len(mapping.Files))
|
||||
@@ -159,7 +160,7 @@ func (r *Resolver) resolveTUFPolicy(mapping *config.PolicyMapping, imageName str
|
||||
|
||||
func (r *Resolver) resolvePolicyByID() (*Policy, error) {
|
||||
if r.opts.PolicyID != "" {
|
||||
localMappings, err := config.LoadLocalMappings(r.opts.LocalPolicyDir)
|
||||
localMappings, err := mapping.LoadLocalMappings(r.opts.LocalPolicyDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load local policy mappings: %w", err)
|
||||
}
|
||||
@@ -171,7 +172,7 @@ func (r *Resolver) resolvePolicyByID() (*Policy, error) {
|
||||
}
|
||||
|
||||
if !r.opts.DisableTUF {
|
||||
tufMappings, err := config.LoadTUFMappings(r.tufClient, r.opts.LocalTargetsDir)
|
||||
tufMappings, err := mapping.LoadTUFMappings(r.tufClient, r.opts.LocalTargetsDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load tuf policy mappings by id: %w", err)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/docker/attest/internal/test"
|
||||
"github.com/docker/attest/policy"
|
||||
"github.com/docker/attest/tuf"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -17,7 +18,8 @@ func TestResolvePolicy(t *testing.T) {
|
||||
noLocalPolicyPath := "testdata/policies/no-policy"
|
||||
testPolicyID := "docker-official-images"
|
||||
testImageName := "localhost:5001/test/repo:tag"
|
||||
|
||||
defaultPlatform, err := v1.ParsePlatform("linux/amd64")
|
||||
require.NoError(t, err)
|
||||
testCases := []struct {
|
||||
name string
|
||||
policyPath string
|
||||
@@ -52,7 +54,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
opts.DisableTUF = tc.DisableTUF
|
||||
opts.LocalTargetsDir = tempDir
|
||||
resolver := policy.NewResolver(tufClient, opts)
|
||||
policy, err := resolver.ResolvePolicy(context.Background(), testImageName)
|
||||
policy, err := resolver.ResolvePolicy(context.Background(), testImageName, defaultPlatform)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, policy)
|
||||
if tc.DisableTUF || tc.localOverridesTUF {
|
||||
|
||||
@@ -2,7 +2,7 @@ package policy
|
||||
|
||||
import (
|
||||
"github.com/docker/attest/attestation"
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/docker/attest/mapping"
|
||||
"github.com/docker/attest/tuf"
|
||||
intoto "github.com/in-toto/in-toto-golang/in_toto"
|
||||
)
|
||||
@@ -34,7 +34,7 @@ type Options struct {
|
||||
LocalPolicyDir string
|
||||
PolicyID string
|
||||
ReferrersRepo string
|
||||
AttestationStyle config.AttestationStyle
|
||||
AttestationStyle mapping.AttestationStyle
|
||||
Debug bool
|
||||
AttestationVerifier attestation.Verifier
|
||||
}
|
||||
@@ -42,7 +42,7 @@ type Options struct {
|
||||
type Policy struct {
|
||||
InputFiles []*File
|
||||
Query string
|
||||
Mapping *config.PolicyMapping
|
||||
Mapping *mapping.PolicyMapping
|
||||
ResolvedName string
|
||||
URI string
|
||||
Digest map[string]string
|
||||
|
||||
23
verify.go
23
verify.go
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/attest/attestation"
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/docker/attest/mapping"
|
||||
"github.com/docker/attest/oci"
|
||||
"github.com/docker/attest/policy"
|
||||
"github.com/docker/attest/tuf"
|
||||
@@ -60,7 +60,12 @@ func (verifier *ImageVerifier) Verify(ctx context.Context, src *oci.ImageSpec) (
|
||||
return nil, fmt.Errorf("failed to resolve image name: %w", err)
|
||||
}
|
||||
policyResolver := policy.NewResolver(verifier.tufClient, verifier.opts)
|
||||
resolvedPolicy, err := policyResolver.ResolvePolicy(ctx, imageName)
|
||||
|
||||
platform, err := detailsResolver.ImagePlatform(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get image platform: %w", err)
|
||||
}
|
||||
resolvedPolicy, err := policyResolver.ResolvePolicy(ctx, imageName, platform)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve policy: %w", err)
|
||||
}
|
||||
@@ -72,14 +77,14 @@ func (verifier *ImageVerifier) Verify(ctx context.Context, src *oci.ImageSpec) (
|
||||
}
|
||||
// this is overriding the mapping with a referrers config. Useful for testing if nothing else
|
||||
if verifier.opts.ReferrersRepo != "" {
|
||||
resolvedPolicy.Mapping.Attestations = &config.AttestationConfig{
|
||||
resolvedPolicy.Mapping.Attestations = &mapping.AttestationConfig{
|
||||
Repo: verifier.opts.ReferrersRepo,
|
||||
Style: config.AttestationStyleReferrers,
|
||||
Style: mapping.AttestationStyleReferrers,
|
||||
}
|
||||
} else if verifier.opts.AttestationStyle == config.AttestationStyleAttached {
|
||||
resolvedPolicy.Mapping.Attestations = &config.AttestationConfig{
|
||||
} else if verifier.opts.AttestationStyle == mapping.AttestationStyleAttached {
|
||||
resolvedPolicy.Mapping.Attestations = &mapping.AttestationConfig{
|
||||
Repo: verifier.opts.ReferrersRepo,
|
||||
Style: config.AttestationStyleAttached,
|
||||
Style: mapping.AttestationStyleAttached,
|
||||
}
|
||||
}
|
||||
// because we have a mapping now, we can select a resolver based on its contents (ie. referrers or attached)
|
||||
@@ -120,9 +125,9 @@ func populateDefaultOptions(opts *policy.Options) (err error) {
|
||||
}
|
||||
|
||||
if opts.AttestationStyle == "" {
|
||||
opts.AttestationStyle = config.AttestationStyleReferrers
|
||||
opts.AttestationStyle = mapping.AttestationStyleReferrers
|
||||
}
|
||||
if opts.ReferrersRepo != "" && opts.AttestationStyle != config.AttestationStyleReferrers {
|
||||
if opts.ReferrersRepo != "" && opts.AttestationStyle != mapping.AttestationStyleReferrers {
|
||||
return fmt.Errorf("referrers repo specified but attestation source not set to referrers")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/attest/attestation"
|
||||
"github.com/docker/attest/config"
|
||||
"github.com/docker/attest/internal/test"
|
||||
"github.com/docker/attest/mapping"
|
||||
"github.com/docker/attest/oci"
|
||||
"github.com/docker/attest/policy"
|
||||
"github.com/docker/attest/tlog"
|
||||
@@ -97,7 +97,7 @@ func TestVSA(t *testing.T) {
|
||||
// mocked vsa query should pass
|
||||
policyOpts := &policy.Options{
|
||||
LocalPolicyDir: PassPolicyDir,
|
||||
AttestationStyle: config.AttestationStyleAttached,
|
||||
AttestationStyle: mapping.AttestationStyleAttached,
|
||||
DisableTUF: true,
|
||||
}
|
||||
results, err := Verify(ctx, spec, policyOpts)
|
||||
@@ -152,7 +152,7 @@ func TestVerificationFailure(t *testing.T) {
|
||||
// mocked vsa query should fail
|
||||
policyOpts := &policy.Options{
|
||||
LocalPolicyDir: FailPolicyDir,
|
||||
AttestationStyle: config.AttestationStyleAttached,
|
||||
AttestationStyle: mapping.AttestationStyleAttached,
|
||||
DisableTUF: true,
|
||||
}
|
||||
results, err := Verify(ctx, spec, policyOpts)
|
||||
@@ -273,7 +273,7 @@ func TestDefaultOptions(t *testing.T) {
|
||||
name string
|
||||
tufOpts *tuf.ClientOptions
|
||||
localTargetsDir string
|
||||
attestationStyle config.AttestationStyle
|
||||
attestationStyle mapping.AttestationStyle
|
||||
referrersRepo string
|
||||
expectedError string
|
||||
disableTuf bool
|
||||
@@ -282,9 +282,9 @@ func TestDefaultOptions(t *testing.T) {
|
||||
{name: "empty"},
|
||||
{name: "tufClient provided", tufOpts: &tuf.ClientOptions{MetadataSource: "a", TargetsSource: "b"}},
|
||||
{name: "localTargetsDir provided", localTargetsDir: test.CreateTempDir(t, "", TestTempDir)},
|
||||
{name: "attestationStyle provided", attestationStyle: config.AttestationStyleAttached},
|
||||
{name: "attestationStyle provided", attestationStyle: mapping.AttestationStyleAttached},
|
||||
{name: "referrersRepo provided", referrersRepo: "referrers"},
|
||||
{name: "referrersRepo provided with attached", referrersRepo: "referrers", attestationStyle: config.AttestationStyleAttached, expectedError: "referrers repo specified but attestation source not set to referrers"},
|
||||
{name: "referrersRepo provided with attached", referrersRepo: "referrers", attestationStyle: mapping.AttestationStyleAttached, expectedError: "referrers repo specified but attestation source not set to referrers"},
|
||||
{name: "tuf disabled and no local-policy-dir", disableTuf: true, expectedError: "local policy dir must be set if not using TUF"},
|
||||
{name: "tuf disabled but options set", disableTuf: true, tufOpts: &tuf.ClientOptions{MetadataSource: "a", TargetsSource: "b"}, localPolicyDir: "foo", expectedError: "TUF client options set but TUF disabled"},
|
||||
}
|
||||
@@ -320,7 +320,7 @@ func TestDefaultOptions(t *testing.T) {
|
||||
if tc.attestationStyle != "" {
|
||||
assert.Equal(t, tc.attestationStyle, opts.AttestationStyle)
|
||||
} else {
|
||||
assert.Equal(t, config.AttestationStyleReferrers, opts.AttestationStyle)
|
||||
assert.Equal(t, mapping.AttestationStyleReferrers, opts.AttestationStyle)
|
||||
}
|
||||
|
||||
if tc.tufOpts != nil {
|
||||
|
||||
Reference in New Issue
Block a user