mirror of
				https://github.com/containers/podman.git
				synced 2025-10-31 10:00:01 +08:00 
			
		
		
		
	 61fe95bb4f
			
		
	
	61fe95bb4f
	
	
	
		
			
			We are unmarshaling and re-marshaling JSON, which can _silently_ drop data with the Go design decision.data. Try harder, by using json.RawMessage at least for the data we care about. Alternatively, this could use json.Decoder.DisallowUnknownFields. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
		
			
				
	
	
		
			197 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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)
 | |
| 
 | |
| 	// Invalid input:
 | |
| 	for _, invalid := range []AddPolicyEntriesInput{
 | |
| 		{
 | |
| 			Scope:       "default",
 | |
| 			Type:        "accept",
 | |
| 			PubKeyFiles: []string{"/does-not-make-sense"},
 | |
| 		},
 | |
| 		{
 | |
| 			Scope:       "default",
 | |
| 			Type:        "insecureAcceptAnything",
 | |
| 			PubKeyFiles: []string{"/does-not-make-sense"},
 | |
| 		},
 | |
| 		{
 | |
| 			Scope:       "default",
 | |
| 			Type:        "reject",
 | |
| 			PubKeyFiles: []string{"/does-not-make-sense"},
 | |
| 		},
 | |
| 		{
 | |
| 			Scope:       "default",
 | |
| 			Type:        "signedBy",
 | |
| 			PubKeyFiles: []string{}, // A key is missing
 | |
| 		},
 | |
| 		{
 | |
| 			Scope:       "default",
 | |
| 			Type:        "sigstoreSigned",
 | |
| 			PubKeyFiles: []string{}, // A key is missing
 | |
| 		},
 | |
| 		{
 | |
| 			Scope:       "default",
 | |
| 			Type:        "this-is-unknown",
 | |
| 			PubKeyFiles: []string{},
 | |
| 		},
 | |
| 	} {
 | |
| 		err := AddPolicyEntries(policyPath, invalid)
 | |
| 		assert.Error(t, err, "%#v", invalid)
 | |
| 	}
 | |
| 
 | |
| 	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)
 | |
| 	err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{
 | |
| 		Scope:       "quay.io/sigstore-signed",
 | |
| 		Type:        "sigstoreSigned",
 | |
| 		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()),
 | |
| 				},
 | |
| 				"quay.io/sigstore-signed": {
 | |
| 					xNewPRSigstoreSignedKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()),
 | |
| 					xNewPRSigstoreSignedKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()),
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}, parsedPolicy)
 | |
| 
 | |
| 	// Test that completely unknown JSON is preserved
 | |
| 	jsonWithUnknownData := `{
 | |
|     "default": [
 | |
|         {
 | |
|             "type": "this is unknown",
 | |
| 			"unknown field": "should be preserved"
 | |
|         }
 | |
|     ],
 | |
|     "transports":
 | |
|         {
 | |
|             "docker-daemon":
 | |
|                 {
 | |
|                     "": [{
 | |
| 						"type":"this is unknown 2",
 | |
| 						"unknown field 2": "should be preserved 2"
 | |
| 						}]
 | |
|                 }
 | |
|         }
 | |
| }`
 | |
| 	err = os.WriteFile(policyPath, []byte(jsonWithUnknownData), 0600)
 | |
| 	require.NoError(t, err)
 | |
| 	err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{
 | |
| 		Scope:       "quay.io/innocuous",
 | |
| 		Type:        "signedBy",
 | |
| 		PubKeyFiles: []string{"/1.pub"},
 | |
| 	})
 | |
| 	require.NoError(t, err)
 | |
| 	updatedJSONWithUnknownData, err := os.ReadFile(policyPath)
 | |
| 	require.NoError(t, err)
 | |
| 	// Decode updatedJSONWithUnknownData so that this test does not depend on details of the encoding.
 | |
| 	// To reduce noise in the constants below:
 | |
| 	type a = []interface{}
 | |
| 	type m = map[string]interface{}
 | |
| 	var parsedUpdatedJSON m
 | |
| 	err = json.Unmarshal(updatedJSONWithUnknownData, &parsedUpdatedJSON)
 | |
| 	require.NoError(t, err)
 | |
| 	assert.Equal(t, m{
 | |
| 		"default": a{
 | |
| 			m{
 | |
| 				"type":          "this is unknown",
 | |
| 				"unknown field": "should be preserved",
 | |
| 			},
 | |
| 		},
 | |
| 		"transports": m{
 | |
| 			"docker-daemon": m{
 | |
| 				"": a{
 | |
| 					m{
 | |
| 						"type":            "this is unknown 2",
 | |
| 						"unknown field 2": "should be preserved 2",
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			"docker": m{
 | |
| 				"quay.io/innocuous": a{
 | |
| 					m{
 | |
| 						"type":    "signedBy",
 | |
| 						"keyType": "GPGKeys",
 | |
| 						"keyPath": "/1.pub",
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}, parsedUpdatedJSON)
 | |
| }
 | |
| 
 | |
| // 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
 | |
| }
 | |
| 
 | |
| // xNewPRSignedByKeyPaths is a wrapper for NewPRSignedByKeyPaths which must not fail.
 | |
| func xNewPRSignedByKeyPaths(t *testing.T, keyPaths []string, signedIdentity signature.PolicyReferenceMatch) signature.PolicyRequirement {
 | |
| 	pr, err := signature.NewPRSignedByKeyPaths(signature.SBKeyTypeGPGKeys, keyPaths, signedIdentity)
 | |
| 	require.NoError(t, err)
 | |
| 	return pr
 | |
| }
 | |
| 
 | |
| // xNewPRSigstoreSignedKeyPath is a wrapper for NewPRSigstoreSignedKeyPath which must not fail.
 | |
| func xNewPRSigstoreSignedKeyPath(t *testing.T, keyPath string, signedIdentity signature.PolicyReferenceMatch) signature.PolicyRequirement {
 | |
| 	pr, err := signature.NewPRSigstoreSignedKeyPath(keyPath, signedIdentity)
 | |
| 	require.NoError(t, err)
 | |
| 	return pr
 | |
| }
 |