summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml3
-rw-r--r--CONTRIBUTING.md4
-rw-r--r--cmd/podman/image.go1
-rw-r--r--cmd/podman/trust.go293
-rw-r--r--contrib/gate/Dockerfile2
-rw-r--r--docs/podman-image-trust.1.md81
-rw-r--r--docs/podman-image.1.md1
-rw-r--r--docs/tutorials/podman_tutorial.md6
-rw-r--r--libpod/image/utils.go22
-rw-r--r--libpod/runtime.go5
-rw-r--r--pkg/trust/trust.go250
-rw-r--r--test/e2e/trust_test.go72
-rw-r--r--test/install/Dockerfile.Fedora4
13 files changed, 740 insertions, 4 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 75c9ac89e..7afd8f0b3 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -103,6 +103,9 @@ build_each_commit_task:
depends_on:
- "gating"
+ # $CIRRUS_BASE_BRANCH is only set when testing a PR
+ only_if: $CIRRUS_BRANCH != 'master'
+
gce_instance:
image_project: "libpod-218412"
zone: "us-central1-a" # Required by Cirrus for the time being
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8e921dcf3..32ed94ad4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -192,6 +192,8 @@ from the repository root, with the command:
sudo podman build -t quay.io/libpod/gate:latest -f contrib/gate/Dockerfile .
```
+***N/B:*** **don't miss the dot (.) at the end, it's really important**
+
The container executes 'make' by default, on a copy of the repository.
This avoids changing or leaving build artifacts in your working directory.
Execution does not require any special permissions from the host. However,
@@ -199,7 +201,7 @@ the repository root must be bind-mounted into the container at
'/usr/src/libpod'. For example, running `make lint` is done (from
the repository root) with the command:
-``sudo podman run -it --rm -v $PWD:/usr/src/libpod:z quay.io/libpod/gate:latest lint``
+``sudo podman run -it --rm -v $PWD:/usr/src/libpod:ro --security-opt label=disable quay.io/libpod/gate:latest lint``
### Integration Tests
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index 95af36df5..e978b9cf5 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -19,6 +19,7 @@ var (
rmImageCommand,
saveCommand,
tagCommand,
+ trustCommand,
}
imageDescription = "Manage images"
diff --git a/cmd/podman/trust.go b/cmd/podman/trust.go
new file mode 100644
index 000000000..7c404cd3f
--- /dev/null
+++ b/cmd/podman/trust.go
@@ -0,0 +1,293 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "sort"
+
+ "github.com/containers/image/types"
+ "github.com/containers/libpod/cmd/podman/formats"
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/trust"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/urfave/cli"
+)
+
+var (
+ setTrustFlags = []cli.Flag{
+ cli.StringFlag{
+ Name: "type, t",
+ Usage: "Trust type, accept values: signedBy(default), accept, reject.",
+ Value: "signedBy",
+ },
+ cli.StringSliceFlag{
+ Name: "pubkeysfile, f",
+ Usage: `Path of installed public key(s) to trust for TARGET.
+ Absolute path to keys is added to policy.json. May
+ used multiple times to define multiple public keys.
+ File(s) must exist before using this command.`,
+ },
+ cli.StringFlag{
+ Name: "policypath",
+ Hidden: true,
+ },
+ }
+ showTrustFlags = []cli.Flag{
+ cli.BoolFlag{
+ Name: "raw",
+ Usage: "Output raw policy file",
+ },
+ cli.BoolFlag{
+ Name: "json, j",
+ Usage: "Output as json",
+ },
+ cli.StringFlag{
+ Name: "policypath",
+ Hidden: true,
+ },
+ cli.StringFlag{
+ Name: "registrypath",
+ Hidden: true,
+ },
+ }
+
+ setTrustDescription = "Set default trust policy or add a new trust policy for a registry"
+ setTrustCommand = cli.Command{
+ Name: "set",
+ Usage: "Set default trust policy or a new trust policy for a registry",
+ Description: setTrustDescription,
+ Flags: sortFlags(setTrustFlags),
+ ArgsUsage: "default | REGISTRY[/REPOSITORY]",
+ Action: setTrustCmd,
+ OnUsageError: usageErrorHandler,
+ }
+
+ showTrustDescription = "Display trust policy for the system"
+ showTrustCommand = cli.Command{
+ Name: "show",
+ Usage: "Display trust policy for the system",
+ Description: showTrustDescription,
+ Flags: sortFlags(showTrustFlags),
+ Action: showTrustCmd,
+ ArgsUsage: "",
+ UseShortOptionHandling: true,
+ OnUsageError: usageErrorHandler,
+ }
+
+ trustSubCommands = []cli.Command{
+ setTrustCommand,
+ showTrustCommand,
+ }
+
+ trustDescription = fmt.Sprintf(`Manages the trust policy of the host system. (%s)
+ Trust policy describes a registry scope that must be signed by public keys.`, getDefaultPolicyPath())
+ trustCommand = cli.Command{
+ Name: "trust",
+ Usage: "Manage container image trust policy",
+ Description: trustDescription,
+ ArgsUsage: "{set,show} ...",
+ Subcommands: trustSubCommands,
+ OnUsageError: usageErrorHandler,
+ }
+)
+
+func showTrustCmd(c *cli.Context) error {
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not create runtime")
+ }
+
+ var (
+ policyPath string
+ systemRegistriesDirPath string
+ )
+ if c.IsSet("policypath") {
+ policyPath = c.String("policypath")
+ } else {
+ policyPath = trust.DefaultPolicyPath(runtime.SystemContext())
+ }
+ policyContent, err := ioutil.ReadFile(policyPath)
+ if err != nil {
+ return errors.Wrapf(err, "unable to read %s", policyPath)
+ }
+ if c.IsSet("registrypath") {
+ systemRegistriesDirPath = c.String("registrypath")
+ } else {
+ systemRegistriesDirPath = trust.RegistriesDirPath(runtime.SystemContext())
+ }
+
+ if c.Bool("raw") {
+ _, err := os.Stdout.Write(policyContent)
+ if err != nil {
+ return errors.Wrap(err, "could not read trust policies")
+ }
+ return nil
+ }
+
+ var policyContentStruct trust.PolicyContent
+ if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
+ return errors.Errorf("could not read trust policies")
+ }
+ policyJSON, err := trust.GetPolicyJSON(policyContentStruct, systemRegistriesDirPath)
+ if err != nil {
+ return errors.Wrapf(err, "error reading registry config file")
+ }
+ if c.Bool("json") {
+ var outjson interface{}
+ outjson = policyJSON
+ out := formats.JSONStruct{Output: outjson}
+ return formats.Writer(out).Out()
+ }
+
+ sortedRepos := sortPolicyJSONKey(policyJSON)
+ type policydefault struct {
+ Repo string
+ Trusttype string
+ GPGid string
+ Sigstore string
+ }
+ var policyoutput []policydefault
+ for _, repo := range sortedRepos {
+ repoval := policyJSON[repo]
+ var defaultstruct policydefault
+ defaultstruct.Repo = repo
+ if repoval["type"] != nil {
+ defaultstruct.Trusttype = trustTypeDescription(repoval["type"].(string))
+ }
+ if repoval["keys"] != nil && len(repoval["keys"].([]string)) > 0 {
+ defaultstruct.GPGid = trust.GetGPGId(repoval["keys"].([]string))
+ }
+ if repoval["sigstore"] != nil {
+ defaultstruct.Sigstore = repoval["sigstore"].(string)
+ }
+ policyoutput = append(policyoutput, defaultstruct)
+ }
+ var output []interface{}
+ for _, ele := range policyoutput {
+ output = append(output, interface{}(ele))
+ }
+ out := formats.StdoutTemplateArray{Output: output, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"}
+ return formats.Writer(out).Out()
+}
+
+func setTrustCmd(c *cli.Context) error {
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not create runtime")
+ }
+
+ args := c.Args()
+ if len(args) != 1 {
+ return errors.Errorf("default or a registry name must be specified")
+ }
+ valid, err := image.IsValidImageURI(args[0])
+ if err != nil || !valid {
+ return errors.Wrapf(err, "invalid image uri %s", args[0])
+ }
+
+ trusttype := c.String("type")
+ if !isValidTrustType(trusttype) {
+ return errors.Errorf("invalid choice: %s (choose from 'accept', 'reject', 'signedBy')", trusttype)
+ }
+ if trusttype == "accept" {
+ trusttype = "insecureAcceptAnything"
+ }
+
+ pubkeysfile := c.StringSlice("pubkeysfile")
+ if len(pubkeysfile) == 0 && trusttype == "signedBy" {
+ return errors.Errorf("At least one public key must be defined for type 'signedBy'")
+ }
+
+ var policyPath string
+ if c.IsSet("policypath") {
+ policyPath = c.String("policypath")
+ } else {
+ policyPath = trust.DefaultPolicyPath(runtime.SystemContext())
+ }
+ var policyContentStruct trust.PolicyContent
+ _, err = os.Stat(policyPath)
+ if !os.IsNotExist(err) {
+ policyContent, err := ioutil.ReadFile(policyPath)
+ if err != nil {
+ return errors.Wrapf(err, "unable to read %s", policyPath)
+ }
+ if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
+ return errors.Errorf("could not read trust policies")
+ }
+ }
+ var newReposContent []trust.RepoContent
+ if len(pubkeysfile) != 0 {
+ for _, filepath := range pubkeysfile {
+ newReposContent = append(newReposContent, trust.RepoContent{Type: trusttype, KeyType: "GPGKeys", KeyPath: filepath})
+ }
+ } else {
+ newReposContent = append(newReposContent, trust.RepoContent{Type: trusttype})
+ }
+ if args[0] == "default" {
+ policyContentStruct.Default = newReposContent
+ } else {
+ exists := false
+ for transport, transportval := range policyContentStruct.Transports {
+ _, exists = transportval[args[0]]
+ if exists {
+ policyContentStruct.Transports[transport][args[0]] = newReposContent
+ break
+ }
+ }
+ if !exists {
+ if policyContentStruct.Transports == nil {
+ policyContentStruct.Transports = make(map[string]trust.RepoMap)
+ }
+ if policyContentStruct.Transports["docker"] == nil {
+ policyContentStruct.Transports["docker"] = make(map[string][]trust.RepoContent)
+ }
+ policyContentStruct.Transports["docker"][args[0]] = append(policyContentStruct.Transports["docker"][args[0]], newReposContent...)
+ }
+ }
+
+ data, err := json.MarshalIndent(policyContentStruct, "", " ")
+ if err != nil {
+ return errors.Wrapf(err, "error setting trust policy")
+ }
+ err = ioutil.WriteFile(policyPath, data, 0644)
+ if err != nil {
+ return errors.Wrapf(err, "error setting trust policy")
+ }
+ return nil
+}
+
+var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"}
+
+func trustTypeDescription(trustType string) string {
+ trustDescription, exist := typeDescription[trustType]
+ if !exist {
+ logrus.Warnf("invalid trust type %s", trustType)
+ }
+ return trustDescription
+}
+
+func sortPolicyJSONKey(m map[string]map[string]interface{}) []string {
+ keys := make([]string, len(m))
+ i := 0
+ for k := range m {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+func isValidTrustType(t string) bool {
+ if t == "accept" || t == "insecureAcceptAnything" || t == "reject" || t == "signedBy" {
+ return true
+ }
+ return false
+}
+
+func getDefaultPolicyPath() string {
+ return trust.DefaultPolicyPath(&types.SystemContext{})
+}
diff --git a/contrib/gate/Dockerfile b/contrib/gate/Dockerfile
index 0c0e4aaf9..f9b57a6da 100644
--- a/contrib/gate/Dockerfile
+++ b/contrib/gate/Dockerfile
@@ -1,4 +1,4 @@
-FROM fedora:28
+FROM fedora:29
RUN dnf -y install \
atomic-registries \
btrfs-progs-devel \
diff --git a/docs/podman-image-trust.1.md b/docs/podman-image-trust.1.md
new file mode 100644
index 000000000..24209698c
--- /dev/null
+++ b/docs/podman-image-trust.1.md
@@ -0,0 +1,81 @@
+% podman-image-trust "1"
+
+# NAME
+podman\-trust - Manage container image trust policy
+
+
+# SYNOPSIS
+**podman image trust set|show**
+[**-h**|**--help**]
+[**-j**|**--json**]
+[**--raw**]
+[**-f**|**--pubkeysfile** KEY1 [**f**|**--pubkeysfile** KEY2,...]]
+[**-t**|**--type** signedBy|accept|reject]
+REGISTRY[/REPOSITORY]
+
+# DESCRIPTION
+Manages the trust policy of the host system. Trust policy describes
+a registry scope (registry and/or repository) that must be signed by public keys. Trust
+is defined in **/etc/containers/policy.json**. Trust is enforced when a user attempts to pull
+an image from a registry.
+
+Trust scope is evaluated by most specific to least specific. In other words, policy may
+be defined for an entire registry, but refined for a particular repository in that
+registry. See below for examples.
+
+Trust **type** provides a way to whitelist ("accept") or blacklist
+("reject") registries.
+
+Trust may be updated using the command **podman image trust set** for an existing trust scope.
+
+# OPTIONS
+**-h** **--help**
+ Print usage statement.
+
+**-f** **--pubkeysfile**
+ A path to an exported public key on the local system. Key paths
+ will be referenced in policy.json. Any path may be used but path
+ **/etc/pki/containers** is recommended. Option may be used multiple times to
+ require an image be sigend by multiple keys. One of **--pubkeys** or
+ **--pubkeysfile** is required for **signedBy** type.
+
+**-t** **--type**
+ The trust type for this policy entry. Accepted values:
+ **signedBy** (default): Require signatures with corresponding list of
+ public keys
+ **accept**: do not require any signatures for this
+ registry scope
+ **reject**: do not accept images for this registry scope
+
+# show OPTIONS
+
+**--raw**
+ Output trust policy file as raw JSON
+
+**-j** **--json**
+ Output trust as JSON for machine parsing
+
+# EXAMPLES
+
+Accept all unsigned images from a registry
+
+ podman image trust set --type accept docker.io
+
+Modify default trust policy
+
+ podman image trust set -t reject default
+
+Display system trust policy
+
+ podman image trust show
+
+Display trust policy file
+
+ podman image trust show --raw
+
+Display trust as JSON
+
+ podman image trust show --json
+
+# HISTORY
+December 2018, originally compiled by Qi Wang (qiwan at redhat dot com)
diff --git a/docs/podman-image.1.md b/docs/podman-image.1.md
index 8b812af11..8aa7cee64 100644
--- a/docs/podman-image.1.md
+++ b/docs/podman-image.1.md
@@ -26,6 +26,7 @@ The image command allows you to manage images
| rm | [podman-rm(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
| save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. |
| tag | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. |
+| trust | [podman-image-trust(1)](podman-image-trust.1.md) | Manage container image trust policy.
## SEE ALSO
podman
diff --git a/docs/tutorials/podman_tutorial.md b/docs/tutorials/podman_tutorial.md
index 659973b28..f8332c820 100644
--- a/docs/tutorials/podman_tutorial.md
+++ b/docs/tutorials/podman_tutorial.md
@@ -84,6 +84,12 @@ cd $GOPATH/src/github.com/containernetworking/plugins
sudo mkdir -p /usr/libexec/cni
sudo cp bin/* /usr/libexec/cni
```
+#### Installing CNI config
+Add a most basic network config
+```console
+mkdir -p /etc/cni/net.d
+curl -qsSL https://raw.githubusercontent.com/containers/libpod/master/cni/87-podman-bridge.conflist | tee /etc/cni/net.d/99-loopback.conf
+```
#### Installing runc
```console
git clone https://github.com/opencontainers/runc.git $GOPATH/src/github.com/opencontainers/runc
diff --git a/libpod/image/utils.go b/libpod/image/utils.go
index 9a75ca6dc..b944de1bb 100644
--- a/libpod/image/utils.go
+++ b/libpod/image/utils.go
@@ -2,6 +2,8 @@ package image
import (
"io"
+ "net/url"
+ "regexp"
"strings"
cp "github.com/containers/image/copy"
@@ -117,3 +119,23 @@ func GetAdditionalTags(images []string) ([]reference.NamedTagged, error) {
}
return allTags, nil
}
+
+// IsValidImageURI checks if image name has valid format
+func IsValidImageURI(imguri string) (bool, error) {
+ uri := "http://" + imguri
+ u, err := url.Parse(uri)
+ if err != nil {
+ return false, errors.Wrapf(err, "invalid image uri: %s", imguri)
+ }
+ reg := regexp.MustCompile(`^[a-zA-Z0-9-_\.]+\/?:?[0-9]*[a-z0-9-\/:]*$`)
+ ret := reg.FindAllString(u.Host, -1)
+ if len(ret) == 0 {
+ return false, errors.Wrapf(err, "invalid image uri: %s", imguri)
+ }
+ reg = regexp.MustCompile(`^[a-z0-9-:\./]*$`)
+ ret = reg.FindAllString(u.Fragment, -1)
+ if len(ret) == 0 {
+ return false, errors.Wrapf(err, "invalid image uri: %s", imguri)
+ }
+ return true, nil
+}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 82473aae9..2dfebf565 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -877,3 +877,8 @@ func (r *Runtime) generateName() (string, error) {
func (r *Runtime) ImageRuntime() *image.Runtime {
return r.imageRuntime
}
+
+// SystemContext returns the imagecontext
+func (r *Runtime) SystemContext() *types.SystemContext {
+ return r.imageContext
+}
diff --git a/pkg/trust/trust.go b/pkg/trust/trust.go
new file mode 100644
index 000000000..efc760364
--- /dev/null
+++ b/pkg/trust/trust.go
@@ -0,0 +1,250 @@
+package trust
+
+import (
+ "bufio"
+ "encoding/base64"
+ "encoding/json"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "unsafe"
+
+ "github.com/containers/image/types"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ yaml "gopkg.in/yaml.v2"
+)
+
+// PolicyContent struct for policy.json file
+type PolicyContent struct {
+ Default []RepoContent `json:"default"`
+ Transports TransportsContent `json:"transports"`
+}
+
+// RepoContent struct used under each repo
+type RepoContent struct {
+ Type string `json:"type"`
+ KeyType string `json:"keyType,omitempty"`
+ KeyPath string `json:"keyPath,omitempty"`
+ KeyData string `json:"keyData,omitempty"`
+ SignedIdentity json.RawMessage `json:"signedIdentity,omitempty"`
+}
+
+// RepoMap map repo name to policycontent for each repo
+type RepoMap map[string][]RepoContent
+
+// TransportsContent struct for content under "transports"
+type TransportsContent map[string]RepoMap
+
+// RegistryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all.
+// NOTE: Keep this in sync with docs/registries.d.md!
+type RegistryConfiguration struct {
+ DefaultDocker *RegistryNamespace `json:"default-docker"`
+ // The key is a namespace, using fully-expanded Docker reference format or parent namespaces (per dockerReference.PolicyConfiguration*),
+ Docker map[string]RegistryNamespace `json:"docker"`
+}
+
+// RegistryNamespace defines lookaside locations for a single namespace.
+type RegistryNamespace struct {
+ SigStore string `json:"sigstore"` // For reading, and if SigStoreStaging is not present, for writing.
+ SigStoreStaging string `json:"sigstore-staging"` // For writing only.
+}
+
+// DefaultPolicyPath returns a path to the default policy of the system.
+func DefaultPolicyPath(sys *types.SystemContext) string {
+ systemDefaultPolicyPath := "/etc/containers/policy.json"
+ if sys != nil {
+ if sys.SignaturePolicyPath != "" {
+ return sys.SignaturePolicyPath
+ }
+ if sys.RootForImplicitAbsolutePaths != "" {
+ return filepath.Join(sys.RootForImplicitAbsolutePaths, systemDefaultPolicyPath)
+ }
+ }
+ return systemDefaultPolicyPath
+}
+
+// RegistriesDirPath returns a path to registries.d
+func RegistriesDirPath(sys *types.SystemContext) string {
+ systemRegistriesDirPath := "/etc/containers/registries.d"
+ if sys != nil {
+ if sys.RegistriesDirPath != "" {
+ return sys.RegistriesDirPath
+ }
+ if sys.RootForImplicitAbsolutePaths != "" {
+ return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath)
+ }
+ }
+ return systemRegistriesDirPath
+}
+
+// LoadAndMergeConfig loads configuration files in dirPath
+func LoadAndMergeConfig(dirPath string) (*RegistryConfiguration, error) {
+ mergedConfig := RegistryConfiguration{Docker: map[string]RegistryNamespace{}}
+ dockerDefaultMergedFrom := ""
+ nsMergedFrom := map[string]string{}
+
+ dir, err := os.Open(dirPath)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return &mergedConfig, nil
+ }
+ return nil, err
+ }
+ configNames, err := dir.Readdirnames(0)
+ if err != nil {
+ return nil, err
+ }
+ for _, configName := range configNames {
+ if !strings.HasSuffix(configName, ".yaml") {
+ continue
+ }
+ configPath := filepath.Join(dirPath, configName)
+ configBytes, err := ioutil.ReadFile(configPath)
+ if err != nil {
+ return nil, err
+ }
+ var config RegistryConfiguration
+ err = yaml.Unmarshal(configBytes, &config)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error parsing %s", configPath)
+ }
+ if config.DefaultDocker != nil {
+ if mergedConfig.DefaultDocker != nil {
+ return nil, errors.Errorf(`Error parsing signature storage configuration: "default-docker" defined both in "%s" and "%s"`,
+ dockerDefaultMergedFrom, configPath)
+ }
+ mergedConfig.DefaultDocker = config.DefaultDocker
+ dockerDefaultMergedFrom = configPath
+ }
+ for nsName, nsConfig := range config.Docker { // includes config.Docker == nil
+ if _, ok := mergedConfig.Docker[nsName]; ok {
+ return nil, errors.Errorf(`Error parsing signature storage configuration: "docker" namespace "%s" defined both in "%s" and "%s"`,
+ nsName, nsMergedFrom[nsName], configPath)
+ }
+ mergedConfig.Docker[nsName] = nsConfig
+ nsMergedFrom[nsName] = configPath
+ }
+ }
+ return &mergedConfig, nil
+}
+
+// HaveMatchRegistry checks if trust settings for the registry have been configed in yaml file
+func HaveMatchRegistry(key string, registryConfigs *RegistryConfiguration) *RegistryNamespace {
+ searchKey := key
+ if !strings.Contains(searchKey, "/") {
+ val, exists := registryConfigs.Docker[searchKey]
+ if exists {
+ return &val
+ }
+ }
+ for range strings.Split(key, "/") {
+ val, exists := registryConfigs.Docker[searchKey]
+ if exists {
+ return &val
+ }
+ if strings.Contains(searchKey, "/") {
+ searchKey = searchKey[:strings.LastIndex(searchKey, "/")]
+ }
+ }
+ return nil
+}
+
+// CreateTmpFile creates a temp file under dir and writes the content into it
+func CreateTmpFile(dir, pattern string, content []byte) (string, error) {
+ tmpfile, err := ioutil.TempFile(dir, pattern)
+ if err != nil {
+ return "", err
+ }
+ defer tmpfile.Close()
+
+ if _, err := tmpfile.Write(content); err != nil {
+ return "", err
+
+ }
+ return tmpfile.Name(), nil
+}
+
+// GetGPGId return GPG identity, either bracketed <email> or ID string
+// comma separated if more than one key
+func GetGPGId(keys []string) string {
+ for _, k := range keys {
+ if _, err := os.Stat(k); err != nil {
+ decodeKey, err := base64.StdEncoding.DecodeString(k)
+ if err != nil {
+ logrus.Warnf("error decoding key data")
+ continue
+ }
+ tmpfileName, err := CreateTmpFile("/run/", "", decodeKey)
+ if err != nil {
+ logrus.Warnf("error creating key date temp file %s", err)
+ }
+ defer os.Remove(tmpfileName)
+ k = tmpfileName
+ }
+ cmd := exec.Command("gpg2", "--with-colons", k)
+ results, err := cmd.Output()
+ if err != nil {
+ logrus.Warnf("error get key identity: %s", err)
+ continue
+ }
+ resultsStr := *(*string)(unsafe.Pointer(&results))
+ scanner := bufio.NewScanner(strings.NewReader(resultsStr))
+ var parseduids []string
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "uid:") || strings.HasPrefix(line, "pub:") {
+ uid := strings.Split(line, ":")[9]
+ if uid == "" {
+ continue
+ }
+ parseduid := uid
+ if strings.Contains(uid, "<") && strings.Contains(uid, ">") {
+ parseduid = strings.SplitN(strings.SplitAfterN(uid, "<", 2)[1], ">", 2)[0]
+ }
+ parseduids = append(parseduids, parseduid)
+ }
+ }
+ return strings.Join(parseduids, ",")
+ }
+ return ""
+}
+
+// GetPolicyJSON return the struct to show policy.json in json format
+func GetPolicyJSON(policyContentStruct PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, error) {
+ registryConfigs, err := LoadAndMergeConfig(systemRegistriesDirPath)
+ if err != nil {
+ return nil, err
+ }
+
+ policyJSON := make(map[string]map[string]interface{})
+ if len(policyContentStruct.Default) > 0 {
+ policyJSON["* (default)"] = make(map[string]interface{})
+ policyJSON["* (default)"]["type"] = policyContentStruct.Default[0].Type
+ }
+ for transname, transval := range policyContentStruct.Transports {
+ for repo, repoval := range transval {
+ policyJSON[repo] = make(map[string]interface{})
+ policyJSON[repo]["type"] = repoval[0].Type
+ policyJSON[repo]["transport"] = transname
+ for _, repoele := range repoval {
+ keyarr := []string{}
+ if len(repoele.KeyPath) > 0 {
+ keyarr = append(keyarr, repoele.KeyPath)
+ }
+ if len(repoele.KeyData) > 0 {
+ keyarr = append(keyarr, string(repoele.KeyData))
+ }
+ policyJSON[repo]["keys"] = keyarr
+ }
+ policyJSON[repo]["sigstore"] = ""
+ registryNamespace := HaveMatchRegistry(repo, registryConfigs)
+ if registryNamespace != nil {
+ policyJSON[repo]["sigstore"] = registryNamespace.SigStore
+ }
+ }
+ }
+ return policyJSON, nil
+}
diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go
new file mode 100644
index 000000000..bbf09eca4
--- /dev/null
+++ b/test/e2e/trust_test.go
@@ -0,0 +1,72 @@
+package integration
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ . "github.com/containers/libpod/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman trust", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanTestCreate(tempdir)
+ podmanTest.RestoreAllArtifacts()
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
+ GinkgoWriter.Write([]byte(timedResult))
+ })
+
+ It("podman image trust show", func() {
+ path, err := os.Getwd()
+ if err != nil {
+ os.Exit(1)
+ }
+ session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Dir(path), "--policypath", filepath.Join(filepath.Dir(path), "policy.json")})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ outArray := session.OutputToStringArray()
+ Expect(len(outArray)).To(Equal(3))
+ Expect(outArray[0]).Should(ContainSubstring("accept"))
+ Expect(outArray[1]).Should(ContainSubstring("reject"))
+ Expect(outArray[2]).Should(ContainSubstring("signed"))
+ })
+
+ It("podman image trust set", func() {
+ path, err := os.Getwd()
+ if err != nil {
+ os.Exit(1)
+ }
+ session := podmanTest.Podman([]string{"image", "trust", "set", "--policypath", filepath.Join(filepath.Dir(path), "trust_set_test.json"), "-t", "accept", "default"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ var teststruct map[string][]map[string]string
+ policyContent, err := ioutil.ReadFile(filepath.Join(filepath.Dir(path), "trust_set_test.json"))
+ if err != nil {
+ os.Exit(1)
+ }
+ err = json.Unmarshal(policyContent, &teststruct)
+ if err != nil {
+ os.Exit(1)
+ }
+ Expect(teststruct["default"][0]["type"]).To(Equal("insecureAcceptAnything"))
+ })
+})
diff --git a/test/install/Dockerfile.Fedora b/test/install/Dockerfile.Fedora
index 188e60328..3a7b472de 100644
--- a/test/install/Dockerfile.Fedora
+++ b/test/install/Dockerfile.Fedora
@@ -1,3 +1,3 @@
-FROM registry.fedoraproject.org/fedora:28
+FROM registry.fedoraproject.org/fedora:29
-RUN dnf install -y rpms/noarch/* rpms/x86_64/* \ No newline at end of file
+RUN dnf install -y rpms/noarch/* rpms/x86_64/*