diff --git a/autofix-extra-resources-ingress_v1.yml b/autofix-extra-resources-ingress_v1.yml new file mode 100644 index 00000000..e69de29b diff --git a/cmd/autofix.go b/cmd/autofix.go index 2a3e5bec..ee77b4dd 100644 --- a/cmd/autofix.go +++ b/cmd/autofix.go @@ -6,6 +6,9 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + k8sRuntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/scheme" ) // The fix function does not preserve comments (because kubernetes resources do not support comments) so we convert @@ -18,7 +21,7 @@ func autofix(*cobra.Command, []string) { resources, err := getKubeResourcesManifest(rootConfig.manifest) - fixedResources := fix(resources) + fixedResources, extraResources := fix(resources) tmpFixedFile, err := ioutil.TempFile("", "kubeaudit_autofix_fixed") if err != nil { @@ -35,11 +38,14 @@ func autofix(*cobra.Command, []string) { log.Error(err) } defer os.Remove(finalFile.Name()) + if err != nil { + log.Error(err) + } splitResources, toAppend, err := splitYamlResources(rootConfig.manifest, finalFile.Name()) for index := range fixedResources { - err = writeSingleResourceManifestFile(fixedResources[index], tmpFixedFile.Name()) + err = WriteToFile(fixedResources[index], tmpFixedFile.Name(), false) if err != nil { log.Error(err) } @@ -57,6 +63,20 @@ func autofix(*cobra.Command, []string) { } toAppend = true } + for index := range extraResources { + info, _ := k8sRuntime.SerializerInfoForMediaType(scheme.Codecs.SupportedMediaTypes(), "application/yaml") + groupVersion := schema.GroupVersion{Group: extraResources[index].GetObjectKind().GroupVersionKind().Group, Version: extraResources[index].GetObjectKind().GroupVersionKind().Version} + encoder := scheme.Codecs.EncoderForVersion(info.Serializer, groupVersion) + fixedData, err := k8sRuntime.Encode(encoder, extraResources[index]) + if err != nil { + log.Error(err) + } + err = writeManifestFile(fixedData, finalFile.Name(), toAppend) + if err != nil { + log.Error(err) + } + toAppend = true + } finalData, err := ioutil.ReadFile(finalFile.Name()) if err != nil { diff --git a/cmd/autofix_test.go b/cmd/autofix_test.go index c5600617..417e430e 100644 --- a/cmd/autofix_test.go +++ b/cmd/autofix_test.go @@ -13,27 +13,108 @@ import ( func TestFixV1(t *testing.T) { file := "../fixtures/autofix_v1.yml" fileFixed := "../fixtures/autofix-fixed_v1.yml" + rootConfig.manifest = file assert := assert.New(t) resources, err := getKubeResourcesManifest(file) assert.Nil(err) - fixedResources := fix(resources) + fixedResources, _ := fix(resources) correctlyFixedResources, err := getKubeResourcesManifest(fileFixed) assert.Nil(err) assertEqualWorkloads(assert, correctlyFixedResources, fixedResources) } +func TestAllResourcesFixV1(t *testing.T) { + file := "../fixtures/autofix-all-resources_v1.yml" + fileFixedResources := "../fixtures/autofix-fixed_v1.yml" + fileExtraResources := "../fixtures/autofix-extra-resources-fixed_v1.yml" + rootConfig.manifest = file + assert := assert.New(t) + resources, err := getKubeResourcesManifest(file) + assert.Nil(err) + fixedResources, extraResources := fix(resources) + correctlyFixedResources, err := getKubeResourcesManifest(fileFixedResources) + assert.Nil(err) + correctlyFixedExtraResources, err := getKubeResourcesManifest(fileExtraResources) + assertEqualWorkloads(assert, correctlyFixedResources, fixedResources) + assertEqualWorkloads(assert, correctlyFixedExtraResources, extraResources) +} + +func TestExtraResourcesFixV1(t *testing.T) { + file := "../fixtures/autofix-extra-resources_v1.yml" + fileFixed := "../fixtures/autofix-extra-resources-fixed_v1.yml" + rootConfig.manifest = file + assert := assert.New(t) + resources, err := getKubeResourcesManifest(file) + assert.Nil(err) + _, extraResources := fix(resources) + correctlyFixedResources, err := getKubeResourcesManifest(fileFixed) + assert.Nil(err) + assertEqualWorkloads(assert, correctlyFixedResources, extraResources) +} + +func TestExtraResourcesEgressFixV1(t *testing.T) { + file := "../fixtures/autofix-extra-resources-egress_v1.yml" + fileFixed := "../fixtures/autofix-extra-resources-egress-fixed_v1.yml" + rootConfig.manifest = file + assert := assert.New(t) + resources, err := getKubeResourcesManifest(file) + assert.Nil(err) + _, extraResources := fix(resources) + correctlyFixedResources, err := getKubeResourcesManifest(fileFixed) + assert.Nil(err) + assertEqualWorkloads(assert, correctlyFixedResources, extraResources) + +} + +func TestExtraResourcesIngressFixV1(t *testing.T) { + file := "../fixtures/autofix-extra-resources-ingress_v1.yml" + fileFixed := "../fixtures/autofix-extra-resources-ingress-fixed_v1.yml" + rootConfig.manifest = file + assert := assert.New(t) + resources, err := getKubeResourcesManifest(file) + assert.Nil(err) + _, extraResources := fix(resources) + correctlyFixedResources, err := getKubeResourcesManifest(fileFixed) + assert.Nil(err) + assertEqualWorkloads(assert, correctlyFixedResources, extraResources) +} + func TestFixV1Beta1(t *testing.T) { file := "../fixtures/autofix_v1beta1.yml" fileFixed := "../fixtures/autofix-fixed_v1beta1.yml" assert := assert.New(t) resources, err := getKubeResourcesManifest(file) assert.Nil(err) - fixedResources := fix(resources) + fixedResources, _ := fix(resources) correctlyFixedResources, err := getKubeResourcesManifest(fileFixed) assert.Nil(err) assertEqualWorkloads(assert, correctlyFixedResources, fixedResources) } +func TestFixV1Beta2(t *testing.T) { + origFilename := "../fixtures/autofix-all-resources_v1.yml" + expectedFilename := "../fixtures/autofix-all-resources-fixed_v1.yml" + assert := assert.New(t) + + // Copy original yaml to a temp file because autofix modifies the input file + tmpFile, err := ioutil.TempFile("", "kubeaudit_autofix_test") + tmpFilename := tmpFile.Name() + assert.Nil(err) + defer os.Remove(tmpFilename) + origFile, err := os.Open(origFilename) + assert.Nil(err) + _, err = io.Copy(tmpFile, origFile) + assert.Nil(err) + tmpFile.Close() + origFile.Close() + + rootConfig.manifest = tmpFilename + autofix(nil, nil) + + assert.True(compareTextFiles(expectedFilename, tmpFilename)) + +} + func TestPreserveComments(t *testing.T) { origFilename := "../fixtures/autofix_v1.yml" expectedFilename := "../fixtures/autofix-fixed_v1.yml" diff --git a/cmd/autofix_util.go b/cmd/autofix_util.go index e0499b20..decfb50e 100644 --- a/cmd/autofix_util.go +++ b/cmd/autofix_util.go @@ -13,12 +13,13 @@ func getAuditFunctions() []interface{} { return []interface{}{ auditAllowPrivilegeEscalation, auditReadOnlyRootFS, auditRunAsNonRoot, auditAutomountServiceAccountToken, auditPrivileged, auditCapabilities, - auditAppArmor, auditSeccomp, + auditAppArmor, auditSeccomp, auditNetworkPolicies, } } func fixPotentialSecurityIssue(resource Resource, result Result) Resource { resource = prepareResourceForFix(resource, result) + for _, occurrence := range result.Occurrences { switch occurrence.id { case ErrorAllowPrivilegeEscalationNil, ErrorAllowPrivilegeEscalationTrue: @@ -42,6 +43,8 @@ func fixPotentialSecurityIssue(resource Resource, result Result) Resource { case ErrorSeccompAnnotationMissing, ErrorSeccompDeprecated, ErrorSeccompDeprecatedPod, ErrorSeccompDisabled, ErrorSeccompDisabledPod: resource = fixSeccomp(resource) + case ErrorMissingDefaultDenyIngressNetworkPolicy, ErrorMissingDefaultDenyEgressNetworkPolicy, ErrorMissingDefaultDenyIngressAndEgressNetworkPolicy: + resource = fixNetworkPolicy(resource, occurrence) } } return resource @@ -78,7 +81,7 @@ func prepareResourceForFix(resource Resource, result Result) Resource { return resource } -func fix(resources []Resource) (fixedResources []Resource) { +func fix(resources []Resource) (fixedResources []Resource, extraResources []Resource) { for _, resource := range resources { if !IsSupportedResourceType(resource) { fixedResources = append(fixedResources, resource) @@ -86,7 +89,15 @@ func fix(resources []Resource) (fixedResources []Resource) { } results := mergeAuditFunctions(getAuditFunctions())(resource) for _, result := range results { - resource = fixPotentialSecurityIssue(resource, result) + if IsNamespaceType(resource) { + extraResource := fixPotentialSecurityIssue(resource, result) + // If return resource from fixPotentialSecurityIssue is Namespace type then we don't have to add extra resources for it. + if !IsNamespaceType(extraResource) { + extraResources = append(extraResources, extraResource) + } + } else { + resource = fixPotentialSecurityIssue(resource, result) + } } fixedResources = append(fixedResources, resource) } diff --git a/cmd/cronjob_test.go b/cmd/cronjob_test.go index 4d9b7d19..815068c1 100644 --- a/cmd/cronjob_test.go +++ b/cmd/cronjob_test.go @@ -14,7 +14,7 @@ func TestCronjobV1(t *testing.T) { assert := assert.New(t) resources, err := getKubeResourcesManifest(file) assert.Nil(err) - fixedResources := fix(resources) + fixedResources, _ := fix(resources) correctlyFixedResources, err := getKubeResourcesManifest(fileFixed) assert.Nil(err) assert.Nil(deep.Equal(correctlyFixedResources, fixedResources)) diff --git a/cmd/errors.go b/cmd/errors.go index fec8df9b..c3e65b01 100644 --- a/cmd/errors.go +++ b/cmd/errors.go @@ -83,6 +83,8 @@ const ( ErrorSeccompDeprecated // InfoImageCorrect occurs when an image tag is correct. InfoImageCorrect + // ErrorMissingDefaultDenyIngressAndEgressNetworkPolicy missing a default deny egress and default deny egress NetworkPolicy + ErrorMissingDefaultDenyIngressAndEgressNetworkPolicy // ErrorMissingDefaultDenyEgressNetworkPolicy occurs when a namespace is missing a default deny egress NetworkPolicy ErrorMissingDefaultDenyEgressNetworkPolicy // ErrorMissingDefaultDenyEgressNetworkPolicy occurs when a namespace is missing a default deny ingress NetworkPolicy diff --git a/cmd/k8sruntime_util.go b/cmd/k8sruntime_util.go index 21db327c..81a969a1 100644 --- a/cmd/k8sruntime_util.go +++ b/cmd/k8sruntime_util.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" + networking "k8s.io/api/networking/v1" k8sRuntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes/scheme" @@ -48,6 +49,18 @@ func setContainers(resource Resource, containers []ContainerV1) Resource { return resource } +func setNetworkPolicyFields(nsName string, policyList []string) Resource { + var np NetworkPolicyV1 + np.Kind = "NetworkPolicy" + np.APIVersion = "networking.k8s.io/v1" + np.ObjectMeta.Namespace = nsName + np.ObjectMeta.Name = "default-deny" + for _, policy := range policyList { + np.Spec.PolicyTypes = append(np.Spec.PolicyTypes, networking.PolicyType(policy)) + } + return np.DeepCopyObject() +} + func disableDSA(resource Resource) Resource { switch t := resource.(type) { case *CronJobV1Beta1: diff --git a/cmd/networkPolicies.go b/cmd/networkPolicies.go index d4a1cadd..44bfa19d 100644 --- a/cmd/networkPolicies.go +++ b/cmd/networkPolicies.go @@ -95,23 +95,28 @@ func checkNamespaceNetworkPolicies(netPols *NetworkPolicyListV1, result *Result) } } } - - if !hasDenyAllIngressRule { + if !hasDenyAllEgressRule && !hasDenyAllIngressRule { + occ := Occurrence{ + container: "", + id: ErrorMissingDefaultDenyIngressAndEgressNetworkPolicy, + kind: Error, + message: "Namespace is missing a default deny ingress and default deny egress NetworkPolicy", + } + result.Occurrences = append(result.Occurrences, occ) + } else if !hasDenyAllIngressRule { occ := Occurrence{ container: "", id: ErrorMissingDefaultDenyIngressNetworkPolicy, kind: Error, - message: "Namespace is missing a default deny egress NetworkPolicy", + message: "Namespace is missing a default deny ingress NetworkPolicy", } result.Occurrences = append(result.Occurrences, occ) - } - - if !hasDenyAllEgressRule { + } else if !hasDenyAllEgressRule { occ := Occurrence{ container: "", id: ErrorMissingDefaultDenyEgressNetworkPolicy, kind: Error, - message: "Namespace is missing a default deny ingress NetworkPolicy", + message: "Namespace is missing a default deny egress NetworkPolicy", } result.Occurrences = append(result.Occurrences, occ) @@ -142,7 +147,9 @@ func getNetworkPoliciesResources(namespace string) (netPolList *NetworkPolicyLis for _, resource := range resources { switch kubeType := resource.(type) { case *NetworkPolicyV1: - netPolList.Items = append(netPolList.Items, *kubeType) + if kubeType.ObjectMeta.Namespace == namespace { + netPolList.Items = append(netPolList.Items, *kubeType) + } } } diff --git a/cmd/networkPolicies_fixes.go b/cmd/networkPolicies_fixes.go new file mode 100644 index 00000000..59aa5d9a --- /dev/null +++ b/cmd/networkPolicies_fixes.go @@ -0,0 +1,16 @@ +package cmd + +func fixNetworkPolicy(resource Resource, occurrence Occurrence) Resource { + var obj Resource + nsName := getNamespaceName(resource) + if occurrence.id == ErrorMissingDefaultDenyIngressNetworkPolicy { + obj = setNetworkPolicyFields(nsName, []string{"Ingress"}) + } + if occurrence.id == ErrorMissingDefaultDenyEgressNetworkPolicy { + obj = setNetworkPolicyFields(nsName, []string{"Egress"}) + } + if occurrence.id == ErrorMissingDefaultDenyIngressAndEgressNetworkPolicy { + obj = setNetworkPolicyFields(nsName, []string{"Ingress", "Egress"}) + } + return obj +} diff --git a/cmd/networkPolicies_test.go b/cmd/networkPolicies_test.go index 4b23dcc1..f4ede88a 100644 --- a/cmd/networkPolicies_test.go +++ b/cmd/networkPolicies_test.go @@ -3,7 +3,7 @@ package cmd import "testing" func TestNamespaceMissingDefaulDenyNetPol(t *testing.T) { - runAuditTest(t, "namespace_missing_default_deny_netpol.yml", auditNetworkPolicies, []int{ErrorMissingDefaultDenyIngressNetworkPolicy, ErrorMissingDefaultDenyEgressNetworkPolicy}) + runAuditTest(t, "namespace_missing_default_deny_netpol.yml", auditNetworkPolicies, []int{ErrorMissingDefaultDenyIngressAndEgressNetworkPolicy}) } func TestNamespaceMissingDefaultDenyEgressNetPol(t *testing.T) { diff --git a/cmd/test_util.go b/cmd/test_util.go index bceb58e6..09b2e70e 100644 --- a/cmd/test_util.go +++ b/cmd/test_util.go @@ -171,6 +171,20 @@ func compareTextFiles(file1, file2 string) bool { return false } } + f1stat, err := f1.Stat() + if err != nil { + return false + } + + f2stat, err := f2.Stat() + if err != nil { + return false + } + + if f1stat.Size() != f2stat.Size() { + fmt.Printf("File sizes don't match") + return false + } return true } diff --git a/cmd/types.go b/cmd/types.go index 1664b3ef..8eb30b7a 100644 --- a/cmd/types.go +++ b/cmd/types.go @@ -115,3 +115,13 @@ func IsSupportedResourceType(obj Resource) bool { return false } } + +// IsNamespaceType returns true if obj is of NamespaceV1 type +func IsNamespaceType(obj Resource) bool { + switch obj.(type) { + case *NamespaceV1: + return true + default: + return false + } +} diff --git a/cmd/util.go b/cmd/util.go index 8e9cfced..b99a3f4e 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -223,14 +223,6 @@ func writeManifestFile(decoded []byte, filename string, toAppend bool) error { return nil } -func writeSingleResourceManifestFile(decoded Resource, filename string) error { - if err := WriteToFile(decoded, filename, false); err != nil { - log.Error(err) - return err - } - return nil -} - func containerNamesUniq(resource Resource) bool { names := make(map[string]bool) for _, container := range getContainers(resource) { diff --git a/fixtures/autofix-all-resources-fixed_v1.yml b/fixtures/autofix-all-resources-fixed_v1.yml new file mode 100644 index 00000000..2b860cde --- /dev/null +++ b/fixtures/autofix-all-resources-fixed_v1.yml @@ -0,0 +1,98 @@ +# This is a test yaml file +# to be autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: + +--- +apiVersion: apps/v1 # The latest api version for Deployment +# This is a deployment +kind: Deployment +metadata: + creationTimestamp: null # This is autopopulated + name: cababilitiesAdded # capabilitiesAdded comment + namespace: fakeDeploymentSC +spec: + strategy: {} + template: + metadata: + creationTimestamp: null # This is also autopopulated + labels: + apps: fakeSecurityContext + annotations: + container.apparmor.security.beta.kubernetes.io/fakeContainerSC1: runtime/default + container.apparmor.security.beta.kubernetes.io/fakeContainerSC2: runtime/default + seccomp.security.alpha.kubernetes.io/pod: runtime/default + spec: + containers: + - name: fakeContainerSC1 # map list item comment + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - AUDIT_WRITE # string list item comment + - CHOWN + - DAC_OVERRIDE + - FOWNER + - FSETID + - KILL + - MKNOD + - NET_BIND_SERVICE + - NET_RAW + - SETFCAP + - SETGID + - SETPCAP + - SETUID + - SYS_CHROOT + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + resources: {} + - name: fakeContainerSC2 + resources: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - AUDIT_WRITE + - CHOWN + - DAC_OVERRIDE + - FOWNER + - FSETID + - KILL + - MKNOD + - NET_BIND_SERVICE + - NET_RAW + - SETFCAP + - SETGID + - SETPCAP + - SETUID + - SYS_CHROOT + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + automountServiceAccountToken: false + selector: null +status: {} +# Post doc comment +--- +apiVersion: v1 +kind: Namespace +metadata: + name: default + creationTimestamp: null +spec: {} +status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: default-deny + namespace: default +spec: + podSelector: {} + policyTypes: + - Ingress + - Egress diff --git a/fixtures/autofix-all-resources_v1.yml b/fixtures/autofix-all-resources_v1.yml new file mode 100644 index 00000000..d9b14d88 --- /dev/null +++ b/fixtures/autofix-all-resources_v1.yml @@ -0,0 +1,44 @@ +# This is a test yaml file +# to be autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: + +--- + +apiVersion: apps/v1 # The latest api version for Deployment +# This is a deployment +kind: Deployment +metadata: + creationTimestamp: null # This is autopopulated + name: cababilitiesAdded # capabilitiesAdded comment + namespace: fakeDeploymentSC +spec: + strategy: {} + template: + metadata: + creationTimestamp: null # This is also autopopulated + labels: + apps: fakeSecurityContext + spec: + containers: + - name: fakeContainerSC1 # map list item comment + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - AUDIT_WRITE # string list item comment + - name: fakeContainerSC2 + +# Post doc comment + +--- + +apiVersion: v1 +kind: Namespace +metadata: + name: default + creationTimestamp: null +spec: {} +status: {} diff --git a/fixtures/autofix-extra-resources-egress-fixed_v1.yml b/fixtures/autofix-extra-resources-egress-fixed_v1.yml new file mode 100644 index 00000000..f3c13ae7 --- /dev/null +++ b/fixtures/autofix-extra-resources-egress-fixed_v1.yml @@ -0,0 +1,17 @@ +# This is a test yaml after it's been autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: default-deny + namespace: default +spec: + podSelector: {} + policyTypes: + - Egress diff --git a/fixtures/autofix-extra-resources-egress_v1.yml b/fixtures/autofix-extra-resources-egress_v1.yml new file mode 100644 index 00000000..609dd430 --- /dev/null +++ b/fixtures/autofix-extra-resources-egress_v1.yml @@ -0,0 +1,25 @@ +# This is a test yaml file +# to be autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: +--- +apiVersion: v1 +kind: Namespace +metadata: + name: default + creationTimestamp: null +spec: {} +status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: default-deny + namespace: default +spec: + podSelector: {} + policyTypes: + - Ingress diff --git a/fixtures/autofix-extra-resources-fixed_v1.yml b/fixtures/autofix-extra-resources-fixed_v1.yml new file mode 100644 index 00000000..d13d3bab --- /dev/null +++ b/fixtures/autofix-extra-resources-fixed_v1.yml @@ -0,0 +1,18 @@ +# This is a test yaml file that was autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: default-deny + namespace: default +spec: + podSelector: {} + policyTypes: + - Ingress + - Egress diff --git a/fixtures/autofix-extra-resources-ingress-fixed_v1.yml b/fixtures/autofix-extra-resources-ingress-fixed_v1.yml new file mode 100644 index 00000000..61f2e7c9 --- /dev/null +++ b/fixtures/autofix-extra-resources-ingress-fixed_v1.yml @@ -0,0 +1,17 @@ +# This is a test yaml after it's been autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: default-deny + namespace: default +spec: + podSelector: {} + policyTypes: + - Ingress diff --git a/fixtures/autofix-extra-resources-ingress_v1.yml b/fixtures/autofix-extra-resources-ingress_v1.yml new file mode 100644 index 00000000..a378f75a --- /dev/null +++ b/fixtures/autofix-extra-resources-ingress_v1.yml @@ -0,0 +1,25 @@ +# This is a test yaml file +# to be autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: +--- +apiVersion: v1 +kind: Namespace +metadata: + name: default + creationTimestamp: null +spec: {} +status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: default-deny + namespace: default +spec: + podSelector: {} + policyTypes: + - Egress diff --git a/fixtures/autofix-extra-resources_v1.yml b/fixtures/autofix-extra-resources_v1.yml new file mode 100644 index 00000000..92b81a9d --- /dev/null +++ b/fixtures/autofix-extra-resources_v1.yml @@ -0,0 +1,15 @@ +# This is a test yaml file +# to be autofixed + +%YAML 1.1 +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: + +--- +apiVersion: v1 +kind: Namespace +metadata: + name: default + creationTimestamp: null +spec: {} +status: {} diff --git a/profile.out b/profile.out new file mode 100644 index 00000000..79b28a0b --- /dev/null +++ b/profile.out @@ -0,0 +1 @@ +mode: atomic