aboutsummaryrefslogtreecommitdiff
path: root/pkg/trust
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2022-08-24 21:39:14 +0200
committerMiloslav Trmač <mitr@redhat.com>2022-08-25 01:50:42 +0200
commitcbdbb025a3f6e6e5417cdade032075d679842056 (patch)
tree0430bbab018b9699b22495ecb3ebb0fb3855dd34 /pkg/trust
parent4f68075306efb9381de3c5ea5762a3f843137b56 (diff)
downloadpodman-cbdbb025a3f6e6e5417cdade032075d679842056.tar.gz
podman-cbdbb025a3f6e6e5417cdade032075d679842056.tar.bz2
podman-cbdbb025a3f6e6e5417cdade032075d679842056.zip
Move most of imageEngine.SetTrust to pkg/trust.AddPolicyEntries
This will allow us to write unit tests without setting up the complete Podman runtime (and without the Linux dependency). Also, actually add a basic smoke test of the core functionality. Should not change behavior. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Diffstat (limited to 'pkg/trust')
-rw-r--r--pkg/trust/policy.go74
-rw-r--r--pkg/trust/policy_test.go71
2 files changed, 145 insertions, 0 deletions
diff --git a/pkg/trust/policy.go b/pkg/trust/policy.go
index 62950131d..352be781c 100644
--- a/pkg/trust/policy.go
+++ b/pkg/trust/policy.go
@@ -5,6 +5,7 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io/ioutil"
"os"
@@ -123,3 +124,76 @@ func GetPolicy(policyPath string) (PolicyContent, error) {
}
return policyContentStruct, nil
}
+
+// AddPolicyEntriesInput collects some parameters to AddPolicyEntries,
+// primarily so that the callers use named values instead of just strings in a sequence.
+type AddPolicyEntriesInput struct {
+ Scope string // "default" or a docker/atomic scope name
+ Type string
+ PubKeyFiles []string // For signature enforcement types, paths to public keys files (where the image needs to be signed by at least one key from _each_ of the files). File format depends on Type.
+}
+
+// AddPolicyEntries adds one or more policy entries necessary to implement AddPolicyEntriesInput.
+func AddPolicyEntries(policyPath string, input AddPolicyEntriesInput) error {
+ var (
+ policyContentStruct PolicyContent
+ newReposContent []RepoContent
+ )
+ trustType := input.Type
+ if trustType == "accept" {
+ trustType = "insecureAcceptAnything"
+ }
+
+ pubkeysfile := input.PubKeyFiles
+ if len(pubkeysfile) == 0 && trustType == "signedBy" {
+ return errors.New("at least one public key must be defined for type 'signedBy'")
+ }
+
+ _, err := os.Stat(policyPath)
+ if !os.IsNotExist(err) {
+ policyContent, err := ioutil.ReadFile(policyPath)
+ if err != nil {
+ return err
+ }
+ if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
+ return errors.New("could not read trust policies")
+ }
+ }
+ if len(pubkeysfile) != 0 {
+ for _, filepath := range pubkeysfile {
+ newReposContent = append(newReposContent, RepoContent{Type: trustType, KeyType: "GPGKeys", KeyPath: filepath})
+ }
+ } else {
+ newReposContent = append(newReposContent, RepoContent{Type: trustType})
+ }
+ if input.Scope == "default" {
+ policyContentStruct.Default = newReposContent
+ } else {
+ if len(policyContentStruct.Default) == 0 {
+ return errors.New("default trust policy must be set")
+ }
+ registryExists := false
+ for transport, transportval := range policyContentStruct.Transports {
+ _, registryExists = transportval[input.Scope]
+ if registryExists {
+ policyContentStruct.Transports[transport][input.Scope] = newReposContent
+ break
+ }
+ }
+ if !registryExists {
+ if policyContentStruct.Transports == nil {
+ policyContentStruct.Transports = make(map[string]RepoMap)
+ }
+ if policyContentStruct.Transports["docker"] == nil {
+ policyContentStruct.Transports["docker"] = make(map[string][]RepoContent)
+ }
+ policyContentStruct.Transports["docker"][input.Scope] = append(policyContentStruct.Transports["docker"][input.Scope], newReposContent...)
+ }
+ }
+
+ data, err := json.MarshalIndent(policyContentStruct, "", " ")
+ if err != nil {
+ return fmt.Errorf("error setting trust policy: %w", err)
+ }
+ return ioutil.WriteFile(policyPath, data, 0644)
+}
diff --git a/pkg/trust/policy_test.go b/pkg/trust/policy_test.go
new file mode 100644
index 000000000..1f2f585c8
--- /dev/null
+++ b/pkg/trust/policy_test.go
@@ -0,0 +1,71 @@
+package trust
+
+import (
+ "encoding/json"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/containers/image/v5/signature"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAddPolicyEntries(t *testing.T) {
+ tempDir := t.TempDir()
+ policyPath := filepath.Join(tempDir, "policy.json")
+
+ minimalPolicy := &signature.Policy{
+ Default: []signature.PolicyRequirement{
+ signature.NewPRInsecureAcceptAnything(),
+ },
+ }
+ minimalPolicyJSON, err := json.Marshal(minimalPolicy)
+ require.NoError(t, err)
+ err = os.WriteFile(policyPath, minimalPolicyJSON, 0600)
+ require.NoError(t, err)
+
+ err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{
+ Scope: "default",
+ Type: "reject",
+ })
+ assert.NoError(t, err)
+ err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{
+ Scope: "quay.io/accepted",
+ Type: "accept",
+ })
+ assert.NoError(t, err)
+ err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{
+ Scope: "quay.io/multi-signed",
+ Type: "signedBy",
+ PubKeyFiles: []string{"/1.pub", "/2.pub"},
+ })
+ assert.NoError(t, err)
+
+ // Test that the outcome is consumable, and compare it with the expected values.
+ parsedPolicy, err := signature.NewPolicyFromFile(policyPath)
+ require.NoError(t, err)
+ assert.Equal(t, &signature.Policy{
+ Default: signature.PolicyRequirements{
+ signature.NewPRReject(),
+ },
+ Transports: map[string]signature.PolicyTransportScopes{
+ "docker": {
+ "quay.io/accepted": {
+ signature.NewPRInsecureAcceptAnything(),
+ },
+ "quay.io/multi-signed": {
+ xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()),
+ xNewPRSignedByKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()),
+ },
+ },
+ },
+ }, parsedPolicy)
+}
+
+// xNewPRSignedByKeyPath is a wrapper for NewPRSignedByKeyPath which must not fail.
+func xNewPRSignedByKeyPath(t *testing.T, keyPath string, signedIdentity signature.PolicyReferenceMatch) signature.PolicyRequirement {
+ pr, err := signature.NewPRSignedByKeyPath(signature.SBKeyTypeGPGKeys, keyPath, signedIdentity)
+ require.NoError(t, err)
+ return pr
+}