diff --git a/schema/schema.go b/schema/schema.go index 26b4eed6..fd1921bb 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -23,6 +23,7 @@ import ( "strings" "time" + "github.com/compose-spec/compose-go/v2/utils" "github.com/xeipuuv/gojsonschema" ) @@ -76,14 +77,15 @@ func Validate(config map[string]interface{}) error { // removeSecretsContentProperty removes the content property from secrets // we add the content key here loader/environment.go:66 func removeSecretsContentProperty(config map[string]interface{}) map[string]interface{} { - if secrets, ok := config["secrets"].(map[string]interface{}); ok { + configClone := utils.CloneMap(config) + if secrets, ok := configClone["secrets"].(map[string]interface{}); ok { for _, secret := range secrets { if secretMap, ok := secret.(map[string]interface{}); ok { delete(secretMap, "content") } } } - return config + return configClone } func toError(result *gojsonschema.Result) error { diff --git a/utils/map.go b/utils/map.go new file mode 100644 index 00000000..d45b43ba --- /dev/null +++ b/utils/map.go @@ -0,0 +1,29 @@ +/* + Copyright 2020 The Compose Specification Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package utils + +func CloneMap(config map[string]interface{}) map[string]interface{} { + clone := make(map[string]interface{}) + for k, v := range config { + if vMap, ok := v.(map[string]interface{}); ok { + clone[k] = CloneMap(vMap) + } else { + clone[k] = v + } + } + return clone +} diff --git a/utils/map_test.go b/utils/map_test.go new file mode 100644 index 00000000..484ef634 --- /dev/null +++ b/utils/map_test.go @@ -0,0 +1,53 @@ +/* + Copyright 2020 The Compose Specification Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package utils + +import ( + "reflect" + "testing" +) + +func TestCloneMap(t *testing.T) { + original := map[string]interface{}{ + "key1": "value1", + "key2": map[string]interface{}{ + "nestedKey1": "nestedValue1", + "nestedKey2": map[string]interface{}{ + "nestedNestedKey1": "nestedNestedValue1", + }, + }, + "key3": 42, + } + + clone := CloneMap(original) + + // Check if the clone is deeply equal to the original + if !reflect.DeepEqual(original, clone) { + t.Errorf("Clone is not equal to the original. Expected %v, got %v", original, clone) + } + + // Modify the clone and check if original is unchanged (deep clone verification) + clone["key2"].(map[string]interface{})["nestedKey1"] = "modifiedValue" + if reflect.DeepEqual(original, clone) { + t.Errorf("Original was changed when modifying the clone. Original: %v, Clone: %v", original, clone) + } + + clone["key2"].(map[string]interface{})["nestedKey2"].(map[string]interface{})["nestedNestedKey1"] = "modifiedNestedNestedValue" + if reflect.DeepEqual(original, clone) { + t.Errorf("Original was changed when modifying the nested clone. Original: %v, Clone: %v", original, clone) + } +}