mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Add a unit test for trust.PolicyDescription
Add at least a basic unit test for the various entry types. So that we don't have to actually deal with GPG keys and /usr/bin/gpg*, parametrize the code with a gpgIDReader , and pass a fake one in the unit test. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
@ -53,6 +53,10 @@ func DefaultPolicyPath(sys *types.SystemContext) string {
|
|||||||
return systemDefaultPolicyPath
|
return systemDefaultPolicyPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gpgIDReader returns GPG key IDs of keys stored at the provided path.
|
||||||
|
// It exists only for tests, production code should always use getGPGIdFromKeyPath.
|
||||||
|
type gpgIDReader func(string) []string
|
||||||
|
|
||||||
// createTmpFile creates a temp file under dir and writes the content into it
|
// createTmpFile creates a temp file under dir and writes the content into it
|
||||||
func createTmpFile(dir, pattern string, content []byte) (string, error) {
|
func createTmpFile(dir, pattern string, content []byte) (string, error) {
|
||||||
tmpfile, err := ioutil.TempFile(dir, pattern)
|
tmpfile, err := ioutil.TempFile(dir, pattern)
|
||||||
@ -79,7 +83,7 @@ func getGPGIdFromKeyPath(path string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getGPGIdFromKeyData returns GPG key IDs of keys in the provided keyring.
|
// getGPGIdFromKeyData returns GPG key IDs of keys in the provided keyring.
|
||||||
func getGPGIdFromKeyData(key string) []string {
|
func getGPGIdFromKeyData(idReader gpgIDReader, key string) []string {
|
||||||
decodeKey, err := base64.StdEncoding.DecodeString(key)
|
decodeKey, err := base64.StdEncoding.DecodeString(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("%s, error decoding key data", err)
|
logrus.Errorf("%s, error decoding key data", err)
|
||||||
@ -90,7 +94,7 @@ func getGPGIdFromKeyData(key string) []string {
|
|||||||
logrus.Errorf("Creating key date temp file %s", err)
|
logrus.Errorf("Creating key date temp file %s", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(tmpfileName)
|
defer os.Remove(tmpfileName)
|
||||||
return getGPGIdFromKeyPath(tmpfileName)
|
return idReader(tmpfileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseUids(colonDelimitKeys []byte) []string {
|
func parseUids(colonDelimitKeys []byte) []string {
|
||||||
|
25
pkg/trust/testdata/default.yaml
vendored
Normal file
25
pkg/trust/testdata/default.yaml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# This is a default registries.d configuration file. You may
|
||||||
|
# add to this file or create additional files in registries.d/.
|
||||||
|
#
|
||||||
|
# lookaside: indicates a location that is read and write
|
||||||
|
# lookaside-staging: indicates a location that is only for write
|
||||||
|
#
|
||||||
|
# lookaside and lookaside-staging take a value of the following:
|
||||||
|
# lookaside: {schema}://location
|
||||||
|
#
|
||||||
|
# For reading signatures, schema may be http, https, or file.
|
||||||
|
# For writing signatures, schema may only be file.
|
||||||
|
|
||||||
|
# This is the default signature write location for docker registries.
|
||||||
|
default-docker:
|
||||||
|
# lookaside: file:///var/lib/containers/sigstore
|
||||||
|
lookaside-staging: file:///var/lib/containers/sigstore
|
||||||
|
|
||||||
|
# The 'docker' indicator here is the start of the configuration
|
||||||
|
# for docker registries.
|
||||||
|
#
|
||||||
|
# docker:
|
||||||
|
#
|
||||||
|
# privateregistry.com:
|
||||||
|
# lookaside: http://privateregistry.com/sigstore/
|
||||||
|
# lookaside-staging: /mnt/nfs/privateregistry/sigstore
|
3
pkg/trust/testdata/redhat.yaml
vendored
Normal file
3
pkg/trust/testdata/redhat.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
docker:
|
||||||
|
registry.redhat.io:
|
||||||
|
sigstore: https://registry.redhat.io/containers/sigstore
|
@ -19,18 +19,23 @@ type Policy struct {
|
|||||||
|
|
||||||
// PolicyDescription returns an user-focused description of the policy in policyPath and registries.d data from registriesDirPath.
|
// PolicyDescription returns an user-focused description of the policy in policyPath and registries.d data from registriesDirPath.
|
||||||
func PolicyDescription(policyPath, registriesDirPath string) ([]*Policy, error) {
|
func PolicyDescription(policyPath, registriesDirPath string) ([]*Policy, error) {
|
||||||
|
return policyDescriptionWithGPGIDReader(policyPath, registriesDirPath, getGPGIdFromKeyPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// policyDescriptionWithGPGIDReader is PolicyDescription with a gpgIDReader parameter. It exists only to make testing easier.
|
||||||
|
func policyDescriptionWithGPGIDReader(policyPath, registriesDirPath string, idReader gpgIDReader) ([]*Policy, error) {
|
||||||
policyContentStruct, err := getPolicy(policyPath)
|
policyContentStruct, err := getPolicy(policyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read trust policies: %w", err)
|
return nil, fmt.Errorf("could not read trust policies: %w", err)
|
||||||
}
|
}
|
||||||
res, err := getPolicyShowOutput(policyContentStruct, registriesDirPath)
|
res, err := getPolicyShowOutput(policyContentStruct, registriesDirPath, idReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not show trust policies: %w", err)
|
return nil, fmt.Errorf("could not show trust policies: %w", err)
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPolicyShowOutput(policyContentStruct policyContent, systemRegistriesDirPath string) ([]*Policy, error) {
|
func getPolicyShowOutput(policyContentStruct policyContent, systemRegistriesDirPath string, idReader gpgIDReader) ([]*Policy, error) {
|
||||||
var output []*Policy
|
var output []*Policy
|
||||||
|
|
||||||
registryConfigs, err := loadAndMergeConfig(systemRegistriesDirPath)
|
registryConfigs, err := loadAndMergeConfig(systemRegistriesDirPath)
|
||||||
@ -76,10 +81,10 @@ func getPolicyShowOutput(policyContentStruct policyContent, systemRegistriesDirP
|
|||||||
uids := []string{}
|
uids := []string{}
|
||||||
for _, repoele := range repoval {
|
for _, repoele := range repoval {
|
||||||
if len(repoele.KeyPath) > 0 {
|
if len(repoele.KeyPath) > 0 {
|
||||||
uids = append(uids, getGPGIdFromKeyPath(repoele.KeyPath)...)
|
uids = append(uids, idReader(repoele.KeyPath)...)
|
||||||
}
|
}
|
||||||
if len(repoele.KeyData) > 0 {
|
if len(repoele.KeyData) > 0 {
|
||||||
uids = append(uids, getGPGIdFromKeyData(repoele.KeyData)...)
|
uids = append(uids, getGPGIdFromKeyData(idReader, repoele.KeyData)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tempTrustShowOutput.GPGId = strings.Join(uids, ", ")
|
tempTrustShowOutput.GPGId = strings.Join(uids, ", ")
|
||||||
|
92
pkg/trust/trust_test.go
Normal file
92
pkg/trust/trust_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package trust
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containers/image/v5/signature"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPolicyDescription(t *testing.T) {
|
||||||
|
tempDir := t.TempDir()
|
||||||
|
policyPath := filepath.Join(tempDir, "policy.json")
|
||||||
|
|
||||||
|
// Override getGPGIdFromKeyPath because we don't want to bother with (and spend the unit-test time on) generating valid GPG keys, and running the real GPG binary.
|
||||||
|
// Instead of reading the files at all, just expect file names like /id1,id2,...,idN.pub
|
||||||
|
idReader := func(keyPath string) []string {
|
||||||
|
require.True(t, strings.HasPrefix(keyPath, "/"))
|
||||||
|
require.True(t, strings.HasSuffix(keyPath, ".pub"))
|
||||||
|
return strings.Split(keyPath[1:len(keyPath)-4], ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range []struct {
|
||||||
|
policy *signature.Policy
|
||||||
|
expected []*Policy
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
&signature.Policy{
|
||||||
|
Default: signature.PolicyRequirements{
|
||||||
|
signature.NewPRReject(),
|
||||||
|
},
|
||||||
|
Transports: map[string]signature.PolicyTransportScopes{
|
||||||
|
"docker": {
|
||||||
|
"quay.io/accepted": {
|
||||||
|
signature.NewPRInsecureAcceptAnything(),
|
||||||
|
},
|
||||||
|
"registry.redhat.io": {
|
||||||
|
xNewPRSignedByKeyPath(t, "/redhat.pub", signature.NewPRMMatchRepoDigestOrExact()),
|
||||||
|
},
|
||||||
|
"quay.io/multi-signed": {
|
||||||
|
xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()),
|
||||||
|
xNewPRSignedByKeyPath(t, "/2,3.pub", signature.NewPRMMatchRepoDigestOrExact()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]*Policy{
|
||||||
|
{
|
||||||
|
Transport: "all",
|
||||||
|
Name: "* (default)",
|
||||||
|
RepoName: "default",
|
||||||
|
Type: "reject",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Transport: "repository",
|
||||||
|
Name: "quay.io/accepted",
|
||||||
|
RepoName: "quay.io/accepted",
|
||||||
|
Type: "accept",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Transport: "repository",
|
||||||
|
Name: "quay.io/multi-signed",
|
||||||
|
RepoName: "quay.io/multi-signed",
|
||||||
|
Type: "signed",
|
||||||
|
SignatureStore: "",
|
||||||
|
GPGId: "1, 2, 3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Transport: "repository",
|
||||||
|
Name: "registry.redhat.io",
|
||||||
|
RepoName: "registry.redhat.io",
|
||||||
|
Type: "signed",
|
||||||
|
SignatureStore: "https://registry.redhat.io/containers/sigstore",
|
||||||
|
GPGId: "redhat",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
policyJSON, err := json.Marshal(c.policy)
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = os.WriteFile(policyPath, policyJSON, 0600)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := policyDescriptionWithGPGIDReader(policyPath, "./testdata", idReader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, c.expected, res)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user