aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2022-08-25 01:25:08 +0200
committerMiloslav Trmač <mitr@redhat.com>2022-08-25 01:52:59 +0200
commit61fe95bb4fa7b6f83cd2a013877664db90cd773b (patch)
tree3db81aa08c21a713fec817dbcf5751374680e119 /pkg
parentad0c785f8e0846112b301872ffc8a7ea276c82a5 (diff)
downloadpodman-61fe95bb4fa7b6f83cd2a013877664db90cd773b.tar.gz
podman-61fe95bb4fa7b6f83cd2a013877664db90cd773b.tar.bz2
podman-61fe95bb4fa7b6f83cd2a013877664db90cd773b.zip
Preserve all unknown PolicyRequirement fields on (podman image trust set)
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>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/trust/policy.go30
-rw-r--r--pkg/trust/policy_test.go64
2 files changed, 87 insertions, 7 deletions
diff --git a/pkg/trust/policy.go b/pkg/trust/policy.go
index daa7698b2..326fe17af 100644
--- a/pkg/trust/policy.go
+++ b/pkg/trust/policy.go
@@ -40,6 +40,18 @@ type repoContent struct {
SignedIdentity json.RawMessage `json:"signedIdentity,omitempty"`
}
+// genericPolicyContent is the overall structure of a policy.json file (= c/image/v5/signature.Policy), using generic data for individual requirements.
+type genericPolicyContent struct {
+ Default json.RawMessage `json:"default"`
+ Transports genericTransportsContent `json:"transports,omitempty"`
+}
+
+// genericTransportsContent contains policies for individual transports (= c/image/v5/signature.Policy.Transports), using generic data for individual requirements.
+type genericTransportsContent map[string]genericRepoMap
+
+// genericRepoMap maps a scope name to requirements that apply to that scope (= c/image/v5/signature.PolicyTransportScopes)
+type genericRepoMap map[string]json.RawMessage
+
// DefaultPolicyPath returns a path to the default policy of the system.
func DefaultPolicyPath(sys *types.SystemContext) string {
systemDefaultPolicyPath := "/etc/containers/policy.json"
@@ -152,7 +164,7 @@ type AddPolicyEntriesInput struct {
// AddPolicyEntries adds one or more policy entries necessary to implement AddPolicyEntriesInput.
func AddPolicyEntries(policyPath string, input AddPolicyEntriesInput) error {
var (
- policyContentStruct policyContent
+ policyContentStruct genericPolicyContent
newReposContent []repoContent
)
trustType := input.Type
@@ -188,8 +200,12 @@ func AddPolicyEntries(policyPath string, input AddPolicyEntriesInput) error {
default:
return fmt.Errorf("unknown trust type %q", input.Type)
}
+ newReposJSON, err := json.Marshal(newReposContent)
+ if err != nil {
+ return err
+ }
- _, err := os.Stat(policyPath)
+ _, err = os.Stat(policyPath)
if !os.IsNotExist(err) {
policyContent, err := ioutil.ReadFile(policyPath)
if err != nil {
@@ -200,7 +216,7 @@ func AddPolicyEntries(policyPath string, input AddPolicyEntriesInput) error {
}
}
if input.Scope == "default" {
- policyContentStruct.Default = newReposContent
+ policyContentStruct.Default = json.RawMessage(newReposJSON)
} else {
if len(policyContentStruct.Default) == 0 {
return errors.New("default trust policy must be set")
@@ -209,18 +225,18 @@ func AddPolicyEntries(policyPath string, input AddPolicyEntriesInput) error {
for transport, transportval := range policyContentStruct.Transports {
_, registryExists = transportval[input.Scope]
if registryExists {
- policyContentStruct.Transports[transport][input.Scope] = newReposContent
+ policyContentStruct.Transports[transport][input.Scope] = json.RawMessage(newReposJSON)
break
}
}
if !registryExists {
if policyContentStruct.Transports == nil {
- policyContentStruct.Transports = make(map[string]repoMap)
+ policyContentStruct.Transports = make(map[string]genericRepoMap)
}
if policyContentStruct.Transports["docker"] == nil {
- policyContentStruct.Transports["docker"] = make(map[string][]repoContent)
+ policyContentStruct.Transports["docker"] = make(map[string]json.RawMessage)
}
- policyContentStruct.Transports["docker"][input.Scope] = append(policyContentStruct.Transports["docker"][input.Scope], newReposContent...)
+ policyContentStruct.Transports["docker"][input.Scope] = json.RawMessage(newReposJSON)
}
}
diff --git a/pkg/trust/policy_test.go b/pkg/trust/policy_test.go
index 0f9721722..3952b72c3 100644
--- a/pkg/trust/policy_test.go
+++ b/pkg/trust/policy_test.go
@@ -108,6 +108,70 @@ func TestAddPolicyEntries(t *testing.T) {
},
},
}, 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.