diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 0a84609ab..75406c17a 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -55,7 +55,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: SARIF file path: results.sarif diff --git a/go.mod b/go.mod index 0683a8e24..e5fcf6c02 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/gofrs/flock v0.13.0 github.com/gosuri/uitable v0.0.4 github.com/jmoiron/sqlx v1.4.0 - github.com/lib/pq v1.12.2 + github.com/lib/pq v1.12.3 github.com/mattn/go-shellwords v1.0.12 github.com/moby/term v0.5.2 github.com/opencontainers/go-digest v1.0.0 @@ -35,7 +35,7 @@ require ( github.com/stretchr/testify v1.11.1 github.com/tetratelabs/wazero v1.11.0 go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.49.0 + golang.org/x/crypto v0.50.0 golang.org/x/term v0.42.0 golang.org/x/text v0.36.0 gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 4d46d3ad1..51f77f70b 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,8 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtB github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.12.2 h1:ajJNv84limnK3aPbDIhLtcjrUbqAw/5XNdkuI6KNe/Q= -github.com/lib/pq v1.12.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= +github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= +github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= @@ -385,8 +385,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= diff --git a/pkg/action/action.go b/pkg/action/action.go index 75b6cf8a0..c93950103 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -27,6 +27,7 @@ import ( "path" "path/filepath" "slices" + "sort" "strings" "sync" "text/template" @@ -144,39 +145,6 @@ const ( filenameAnnotation = "postrenderer.helm.sh/postrender-filename" ) -// fixDocSeparators ensures YAML document separators ("---") are always -// followed by a newline in rendered template content. Go template whitespace -// trimming ({{-) can remove the newline after "---", producing e.g. -// "---apiVersion: v1" which is not a valid YAML document separator. -// This function inserts a newline after any "---" at the start of a line -// that is immediately followed by non-whitespace content. -func fixDocSeparators(content string) string { - var b strings.Builder - remaining := content - for { - // Find "---" at the start of a line (or start of content). - idx := strings.Index(remaining, "---") - if idx == -1 { - b.WriteString(remaining) - break - } - // "---" must be at the start of a line: either idx==0 or preceded by '\n'. - if idx > 0 && remaining[idx-1] != '\n' { - b.WriteString(remaining[:idx+3]) - remaining = remaining[idx+3:] - continue - } - b.WriteString(remaining[:idx+3]) - remaining = remaining[idx+3:] - // If "---" is followed by non-whitespace (e.g. "---apiVersion"), - // insert a newline to make it a proper document separator. - if len(remaining) > 0 && remaining[0] != '\n' && remaining[0] != '\r' && remaining[0] != ' ' && remaining[0] != '\t' { - b.WriteByte('\n') - } - } - return b.String() -} - // annotateAndMerge combines multiple YAML files into a single stream of documents, // adding filename annotations to each document for later reconstruction. func annotateAndMerge(files map[string]string) (string, error) { @@ -192,22 +160,32 @@ func annotateAndMerge(files map[string]string) (string, error) { continue } - // Fix document separators where Go template whitespace trimming - // ({{-) has removed the newline after "---", producing e.g. - // "---apiVersion: v1" which is not a valid YAML document - // separator. Insert the missing newline so kio.ParseAll can - // parse the content correctly. - content = fixDocSeparators(content) - - manifests, err := kio.ParseAll(content) - if err != nil { - return "", fmt.Errorf("parsing %s: %w", fname, err) + // For consistency with the non-post-renderers code path, we need + // to use releaseutil.SplitManifests here to split the file into + // individual documents before feeding them to kio.ParseAll. In + // Chart API before v3 this function had leniency for badly-written + // Go templates, so this must be preserved for older charts. + splitDocs := releaseutil.SplitManifests(content) + keys := make([]string, 0, len(splitDocs)) + for k := range splitDocs { + keys = append(keys, k) } - for _, manifest := range manifests { - if err := manifest.PipeE(kyaml.SetAnnotation(filenameAnnotation, fname)); err != nil { - return "", fmt.Errorf("annotating %s: %w", fname, err) + sort.Sort(releaseutil.BySplitManifestsOrder(keys)) + for _, key := range keys { + doc := splitDocs[key] + if strings.TrimSpace(doc) == "" { + continue + } + manifests, err := kio.ParseAll(doc) + if err != nil { + return "", fmt.Errorf("parsing %s: %w", fname, err) + } + for _, manifest := range manifests { + if err := manifest.PipeE(kyaml.SetAnnotation(filenameAnnotation, fname)); err != nil { + return "", fmt.Errorf("annotating %s: %w", fname, err) + } + combinedManifests = append(combinedManifests, manifest) } - combinedManifests = append(combinedManifests, manifest) } } diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 62e8adfea..a2b170206 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -403,96 +403,6 @@ func (m *mockPostRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, return bytes.NewBufferString(content), nil } -func TestFixDocSeparators(t *testing.T) { - tests := []struct { - name string - input string - expected string - }{ - { - name: "no separator", - input: "apiVersion: v1\nkind: Service\n", - expected: "apiVersion: v1\nkind: Service\n", - }, - { - name: "separator on its own line", - input: "---\napiVersion: v1\nkind: Service\n", - expected: "---\napiVersion: v1\nkind: Service\n", - }, - { - name: "leading separator glued to content", - input: "---apiVersion: v1\nkind: Service\n", - expected: "---\napiVersion: v1\nkind: Service\n", - }, - { - name: "mid-content separator glued to content", - input: "apiVersion: v1\nkind: ConfigMap\n---apiVersion: v1\nkind: Service\n", - expected: "apiVersion: v1\nkind: ConfigMap\n---\napiVersion: v1\nkind: Service\n", - }, - { - name: "multiple separators all proper", - input: "---\napiVersion: v1\n---\napiVersion: v1\n", - expected: "---\napiVersion: v1\n---\napiVersion: v1\n", - }, - { - name: "multiple separators some glued", - input: "---apiVersion: v1\nkind: ConfigMap\n---apiVersion: v1\nkind: Service\n", - expected: "---\napiVersion: v1\nkind: ConfigMap\n---\napiVersion: v1\nkind: Service\n", - }, - { - name: "empty string", - input: "", - expected: "", - }, - { - name: "only separator", - input: "---\n", - expected: "---\n", - }, - { - name: "triple dash in a value is not a separator", - input: "data:\n key: ---value\n", - expected: "data:\n key: ---value\n", - }, - { - name: "realistic multi-doc template output", - input: "apiVersion: v1\nkind: Deployment\n---\napiVersion: v1\nkind: Ingress\n---apiVersion: v1\nkind: Service\n", - expected: "apiVersion: v1\nkind: Deployment\n---\napiVersion: v1\nkind: Ingress\n---\napiVersion: v1\nkind: Service\n", - }, - { - name: "separator followed by carriage return", - input: "---\r\napiVersion: v1\n", - expected: "---\r\napiVersion: v1\n", - }, - { - name: "separator followed by space", - input: "--- \napiVersion: v1\n", - expected: "--- \napiVersion: v1\n", - }, - { - name: "separator followed by tab", - input: "---\t\napiVersion: v1\n", - expected: "---\t\napiVersion: v1\n", - }, - { - name: "four dashes on its own line", - input: "----\napiVersion: v1\n", - expected: "---\n-\napiVersion: v1\n", - }, - { - name: "four dashes followed by text", - input: "----more\napiVersion: v1\n", - expected: "---\n-more\napiVersion: v1\n", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.expected, fixDocSeparators(tt.input)) - }) - } -} - func TestAnnotateAndMerge(t *testing.T) { tests := []struct { name string @@ -690,6 +600,339 @@ metadata: name: test-svc annotations: postrenderer.helm.sh/postrender-filename: 'templates/all.yaml' +`, + }, + { + name: "ConfigMap with embedded CA certificate", + files: map[string]string{ + "templates/configmap.yaml": ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: ca-bundle +data: + ca.crt: | + ------BEGIN CERTIFICATE------ + MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zAKBggqhkjOPQQDAzASMRAw + DgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYwMDAw + WjASMRAwDgYDVQQKEwdBY21lIENvMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7Rmm + ------END CERTIFICATE------ + ------BEGIN CERTIFICATE------ + MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zAKBggqhkjOPQQDAzASMRAw + DgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYwMDAw + WjASMRAwDgYDVQQKEwdBY21lIENvMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7Rmm + ------END CERTIFICATE------ +`, + }, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ca-bundle + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/configmap.yaml' +data: + ca.crt: |- + ------BEGIN CERTIFICATE------ + MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zAKBggqhkjOPQQDAzASMRAw + DgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYwMDAw + WjASMRAwDgYDVQQKEwdBY21lIENvMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7Rmm + ------END CERTIFICATE------ + ------BEGIN CERTIFICATE------ + MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zAKBggqhkjOPQQDAzASMRAw + DgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYwMDAw + WjASMRAwDgYDVQQKEwdBY21lIENvMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7Rmm + ------END CERTIFICATE------ +`, + }, + { + name: "consecutive dashes in YAML value are not treated as document separators", + files: map[string]string{ + "templates/configmap.yaml": ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: test-cm +data: + config: | + # --------------------------------------------------------------------------- + [section] + key = value + # --------------------------------------------------------------------------- +`, + }, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: test-cm + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/configmap.yaml' +data: + config: |- + # --------------------------------------------------------------------------- + [section] + key = value + # --------------------------------------------------------------------------- +`, + }, + { + name: "JSON with dashes in values is not corrupted", + files: map[string]string{ + "templates/dashboard.yaml": ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: dashboard +data: + dashboard.json: | + {"options":{"---------":{"color":"#292929","text":"N/A"}}} +`, + }, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: dashboard + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/dashboard.yaml' +data: + dashboard.json: |- + {"options":{"---------":{"color":"#292929","text":"N/A"}}} +`, + }, + + // **Note for Chart API v3**: This input should return an _ERROR_ in Chart API v3. + // See the comment on the releaseutil.SplitManifests function for more details. + { + name: "multiple glued separators in same file", + files: map[string]string{ + "templates/multi.yaml": ` +---apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 +---apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 +---apiVersion: v1 +kind: ConfigMap +metadata: + name: cm3 +`, + }, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/multi.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/multi.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm3 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/multi.yaml' +`, + }, + + // **Note for Chart API v3**: This input should return an _ERROR_ in Chart API v3. + // See the comment on the releaseutil.SplitManifests function for more details. + { + name: "mixed glued and proper separators", + files: map[string]string{ + "templates/mixed.yaml": ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 +---apiVersion: v1 +kind: ConfigMap +metadata: + name: cm3 +`, + }, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/mixed.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/mixed.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm3 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/mixed.yaml' +`, + }, + { + name: "12 documents preserve in-file order", + files: map[string]string{ + "templates/many.yaml": ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-01 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-02 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-03 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-04 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-05 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-06 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-07 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-08 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-09 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-10 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-11 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-12 +`, + }, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-01 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-02 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-03 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-04 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-05 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-06 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-07 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-08 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-09 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-10 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-11 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-12 + annotations: + postrenderer.helm.sh/postrender-filename: 'templates/many.yaml' `, }, } diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index 0639e07fc..73a424720 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -1680,8 +1680,6 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { t.Run("method-specific context overrides general context for WaitForDelete", func(t *testing.T) { t.Parallel() c := newTestClient(t) - timeout := time.Second - timeUntilPodDelete := time.Millisecond * 500 fakeClient := dynamicfake.NewSimpleDynamicClient(scheme.Scheme) fakeMapper := testutil.NewFakeRESTMapper( v1.SchemeGroupVersion.WithKind("Pod"), @@ -1698,27 +1696,14 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { waitForDeleteCtx: context.Background(), // Not cancelled - should be used } + // Use a non-existent resource: WaitForDelete should return immediately since + // the pod is already in the desired "deleted" state. + // This also validates context selection: if generalCtx (cancelled) were + // incorrectly used instead of waitForDeleteCtx, the watch context would be + // immediately cancelled and the call would return a context error. objs := getRuntimeObjFromManifests(t, []string{podCurrentManifest}) - for _, obj := range objs { - u := obj.(*unstructured.Unstructured) - gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) - } - - // Schedule deletion - for _, obj := range objs { - u := obj.(*unstructured.Unstructured) - gvr := getGVR(t, fakeMapper, u) - go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { - time.Sleep(timeUntilPodDelete) - err := fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) - }(gvr, u) - } - resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitForDelete(resourceList, timeout) + err := sw.WaitForDelete(resourceList, time.Second) // Should succeed because method context is used and it's not cancelled assert.NoError(t, err) }) diff --git a/pkg/release/v1/util/manifest.go b/pkg/release/v1/util/manifest.go index 9a87949f8..3160599bc 100644 --- a/pkg/release/v1/util/manifest.go +++ b/pkg/release/v1/util/manifest.go @@ -36,6 +36,15 @@ type SimpleHead struct { var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*") // SplitManifests takes a string of manifest and returns a map contains individual manifests +// +// **Note for Chart API v3**: This function (due to the regex above) has allowed _WRONG_ +// Go templates to be defined inside charts across the years. The generated text from Go +// templates may contain `---apiVersion: v1`, and this function magically splits this back +// to `---\napiVersion: v1`. This has caused issues recently after Helm 4 introduced +// kio.ParseAll to inject annotations when post-renderers are used. In Chart API v3, +// we should kill this regex with fire (or change it) and expose charts doing the wrong +// thing Go template-wise. Helm should say a big _NO_ to charts doing the wrong thing, +// with or without post-renderers. func SplitManifests(bigFile string) map[string]string { // Basically, we're quickly splitting a stream of YAML documents into an // array of YAML docs. The file name is just a place holder, but should be