diff --git a/e2e-tests/mdx-less-babel/cypress/integration/frontmatter.js b/e2e-tests/mdx-less-babel/cypress/integration/frontmatter.js new file mode 100644 index 0000000000000..95804c9b7e9a5 --- /dev/null +++ b/e2e-tests/mdx-less-babel/cypress/integration/frontmatter.js @@ -0,0 +1,91 @@ +const page = { + js: `/frontmatter-js`, + javascript: `/frontmatter-javascript`, + yaml: `/frontmatter-yaml`, + json: `/frontmatter-json`, + graphqlQuery: `/frontmatter-graphql-query`, +} + +// Attribute selector for element we assert against in pages +const selector = `[data-cy="frontmatter"]` + +// Strings used for frontmatter titles +const titles = { + notParsed: `I should not be parsed`, + parsed: `I am parsed`, +} + +// Frontmatter that should not be rendered +const otherKey = `Some other key` + +describe(`webpack loader`, () => { + describe(`---yaml frontmatter`, () => { + beforeEach(() => { + cy.visit(page.yaml).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, titles.parsed) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) + + describe(`---json frontmatter`, () => { + beforeEach(() => { + cy.visit(page.json).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, titles.parsed) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) + + describe(`---js frontmatter`, () => { + beforeEach(() => { + cy.visit(page.js).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, `disabled`) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) + + describe(`---javascript frontmatter`, () => { + beforeEach(() => { + cy.visit(page.javascript).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, `disabled`) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) +}) + +describe(`data layer`, () => { + it(`---js or ---javascript frontmatter should not parse by default`, () => { + cy.visit(page.graphqlQuery).waitForRouteChange() + cy.contains(titles.notParsed).should(`not.exist`) + }) +}) + +it(`---js and ---javascript frontmatter should not allow remote code execution`, () => { + cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should( + `eq`, + `Nothing here, do not remove` + ) +}) diff --git a/e2e-tests/mdx-less-babel/cypress/integration/js-frontmatter.js b/e2e-tests/mdx-less-babel/cypress/integration/js-frontmatter.js deleted file mode 100644 index ac26fcb0aba45..0000000000000 --- a/e2e-tests/mdx-less-babel/cypress/integration/js-frontmatter.js +++ /dev/null @@ -1,29 +0,0 @@ -describe(`webpack loader`, () => { - it(`---js frontmatter should not parse by default`, () => { - cy.visit(`/js-frontmatter`).waitForRouteChange() - - // Check frontmatter not parsed in page context - cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`) - }) - - it(`---javascript frontmatter should not parse by default`, () => { - cy.visit(`/javascript-frontmatter`).waitForRouteChange() - - // Check frontmatter not parsed in page context - cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`) - }) -}) - -describe(`data layer`, () => { - it(`---js or ---javascript frontmatter should not parse by default`, () => { - cy.visit(`/mdx-query-js-frontmatter/`).waitForRouteChange() - cy.contains(`I should not be parsed`).should("not.exist") - }) -}) - -it(`---js and ---javascript frontmatter should not allow remote code execution`, () => { - cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should( - `eq`, - `Nothing here, do not remove` - ) -}) diff --git a/e2e-tests/mdx/src/pages/mdx-query-js-frontmatter.js b/e2e-tests/mdx-less-babel/src/pages/frontmatter-graphql-query.js similarity index 100% rename from e2e-tests/mdx/src/pages/mdx-query-js-frontmatter.js rename to e2e-tests/mdx-less-babel/src/pages/frontmatter-graphql-query.js diff --git a/e2e-tests/mdx/src/pages/javascript-frontmatter.mdx b/e2e-tests/mdx-less-babel/src/pages/frontmatter-javascript.mdx similarity index 80% rename from e2e-tests/mdx/src/pages/javascript-frontmatter.mdx rename to e2e-tests/mdx-less-babel/src/pages/frontmatter-javascript.mdx index 5210c21d086d4..9b4cfa869eaee 100644 --- a/e2e-tests/mdx/src/pages/javascript-frontmatter.mdx +++ b/e2e-tests/mdx-less-babel/src/pages/frontmatter-javascript.mdx @@ -3,7 +3,8 @@ require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack) console.trace() return { -title: `I should not be parsed` +title: `I should not be parsed`, +otherKey: `Some other key` } })() @@ -11,6 +12,6 @@ title: `I should not be parsed`

JS frontmatter engine is disabled by default

- + {props.pageContext.frontmatter?.title || `disabled`} diff --git a/e2e-tests/mdx-less-babel/src/pages/js-frontmatter.mdx b/e2e-tests/mdx-less-babel/src/pages/frontmatter-js.mdx similarity index 79% rename from e2e-tests/mdx-less-babel/src/pages/js-frontmatter.mdx rename to e2e-tests/mdx-less-babel/src/pages/frontmatter-js.mdx index fcb411cdccfda..0496fe83ca8eb 100644 --- a/e2e-tests/mdx-less-babel/src/pages/js-frontmatter.mdx +++ b/e2e-tests/mdx-less-babel/src/pages/frontmatter-js.mdx @@ -3,7 +3,8 @@ require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack) console.trace() return { -title: `I should not be parsed` +title: `I should not be parsed`, +otherKey: `Some other key` } })() @@ -11,6 +12,6 @@ title: `I should not be parsed`

JS frontmatter engine is disabled by default

- + {props.pageContext.frontmatter?.title || `disabled`} diff --git a/e2e-tests/mdx-less-babel/src/pages/frontmatter-json.mdx b/e2e-tests/mdx-less-babel/src/pages/frontmatter-json.mdx new file mode 100644 index 0000000000000..e64f1e0fec826 --- /dev/null +++ b/e2e-tests/mdx-less-babel/src/pages/frontmatter-json.mdx @@ -0,0 +1,8 @@ +---json +{ "title": "I am parsed", "otherKey": "Some other key" } + +--- + +

A page with JSON frontmatter

+ +{props.pageContext.frontmatter?.title} diff --git a/e2e-tests/mdx-less-babel/src/pages/frontmatter-yaml.mdx b/e2e-tests/mdx-less-babel/src/pages/frontmatter-yaml.mdx new file mode 100644 index 0000000000000..baa4ab4363889 --- /dev/null +++ b/e2e-tests/mdx-less-babel/src/pages/frontmatter-yaml.mdx @@ -0,0 +1,9 @@ +---yaml +title: I am parsed +otherKey: Some other key + +--- + +

A page with YAML frontmatter

+ +{props.pageContext.frontmatter?.title} diff --git a/e2e-tests/mdx/cypress/integration/frontmatter.js b/e2e-tests/mdx/cypress/integration/frontmatter.js new file mode 100644 index 0000000000000..95804c9b7e9a5 --- /dev/null +++ b/e2e-tests/mdx/cypress/integration/frontmatter.js @@ -0,0 +1,91 @@ +const page = { + js: `/frontmatter-js`, + javascript: `/frontmatter-javascript`, + yaml: `/frontmatter-yaml`, + json: `/frontmatter-json`, + graphqlQuery: `/frontmatter-graphql-query`, +} + +// Attribute selector for element we assert against in pages +const selector = `[data-cy="frontmatter"]` + +// Strings used for frontmatter titles +const titles = { + notParsed: `I should not be parsed`, + parsed: `I am parsed`, +} + +// Frontmatter that should not be rendered +const otherKey = `Some other key` + +describe(`webpack loader`, () => { + describe(`---yaml frontmatter`, () => { + beforeEach(() => { + cy.visit(page.yaml).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, titles.parsed) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) + + describe(`---json frontmatter`, () => { + beforeEach(() => { + cy.visit(page.json).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, titles.parsed) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) + + describe(`---js frontmatter`, () => { + beforeEach(() => { + cy.visit(page.js).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, `disabled`) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) + + describe(`---javascript frontmatter`, () => { + beforeEach(() => { + cy.visit(page.javascript).waitForRouteChange() + }) + + it(`should parse`, () => { + cy.get(selector).invoke(`text`).should(`eq`, `disabled`) + }) + + it(`should not leak into the page`, () => { + cy.contains(otherKey).should(`not.exist`) + }) + }) +}) + +describe(`data layer`, () => { + it(`---js or ---javascript frontmatter should not parse by default`, () => { + cy.visit(page.graphqlQuery).waitForRouteChange() + cy.contains(titles.notParsed).should(`not.exist`) + }) +}) + +it(`---js and ---javascript frontmatter should not allow remote code execution`, () => { + cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should( + `eq`, + `Nothing here, do not remove` + ) +}) diff --git a/e2e-tests/mdx/cypress/integration/js-frontmatter.js b/e2e-tests/mdx/cypress/integration/js-frontmatter.js deleted file mode 100644 index ac26fcb0aba45..0000000000000 --- a/e2e-tests/mdx/cypress/integration/js-frontmatter.js +++ /dev/null @@ -1,29 +0,0 @@ -describe(`webpack loader`, () => { - it(`---js frontmatter should not parse by default`, () => { - cy.visit(`/js-frontmatter`).waitForRouteChange() - - // Check frontmatter not parsed in page context - cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`) - }) - - it(`---javascript frontmatter should not parse by default`, () => { - cy.visit(`/javascript-frontmatter`).waitForRouteChange() - - // Check frontmatter not parsed in page context - cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`) - }) -}) - -describe(`data layer`, () => { - it(`---js or ---javascript frontmatter should not parse by default`, () => { - cy.visit(`/mdx-query-js-frontmatter/`).waitForRouteChange() - cy.contains(`I should not be parsed`).should("not.exist") - }) -}) - -it(`---js and ---javascript frontmatter should not allow remote code execution`, () => { - cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should( - `eq`, - `Nothing here, do not remove` - ) -}) diff --git a/e2e-tests/mdx/src/pages/frontmatter-graphql-query.js b/e2e-tests/mdx/src/pages/frontmatter-graphql-query.js new file mode 100644 index 0000000000000..c94d169a7699e --- /dev/null +++ b/e2e-tests/mdx/src/pages/frontmatter-graphql-query.js @@ -0,0 +1,30 @@ +import React from "react" +import { graphql } from "gatsby" + +export default function PageRunningGraphqlResolversOnJSFrontmatterTestInputs({ + data, +}) { + return
{JSON.stringify(data.allMdx.nodes, null, 2)}
+} + +export const query = graphql` + { + allMdx(filter: { slug: { glob: "frontmatter-engine/*" } }) { + nodes { + frontmatter { + title + } + body + excerpt + tableOfContents + timeToRead + wordCount { + paragraphs + sentences + words + } + mdxAST + } + } + } +` diff --git a/e2e-tests/mdx-less-babel/src/pages/javascript-frontmatter.mdx b/e2e-tests/mdx/src/pages/frontmatter-javascript.mdx similarity index 80% rename from e2e-tests/mdx-less-babel/src/pages/javascript-frontmatter.mdx rename to e2e-tests/mdx/src/pages/frontmatter-javascript.mdx index 5210c21d086d4..9b4cfa869eaee 100644 --- a/e2e-tests/mdx-less-babel/src/pages/javascript-frontmatter.mdx +++ b/e2e-tests/mdx/src/pages/frontmatter-javascript.mdx @@ -3,7 +3,8 @@ require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack) console.trace() return { -title: `I should not be parsed` +title: `I should not be parsed`, +otherKey: `Some other key` } })() @@ -11,6 +12,6 @@ title: `I should not be parsed`

JS frontmatter engine is disabled by default

- + {props.pageContext.frontmatter?.title || `disabled`} diff --git a/e2e-tests/mdx/src/pages/js-frontmatter.mdx b/e2e-tests/mdx/src/pages/frontmatter-js.mdx similarity index 79% rename from e2e-tests/mdx/src/pages/js-frontmatter.mdx rename to e2e-tests/mdx/src/pages/frontmatter-js.mdx index fcb411cdccfda..0496fe83ca8eb 100644 --- a/e2e-tests/mdx/src/pages/js-frontmatter.mdx +++ b/e2e-tests/mdx/src/pages/frontmatter-js.mdx @@ -3,7 +3,8 @@ require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack) console.trace() return { -title: `I should not be parsed` +title: `I should not be parsed`, +otherKey: `Some other key` } })() @@ -11,6 +12,6 @@ title: `I should not be parsed`

JS frontmatter engine is disabled by default

- + {props.pageContext.frontmatter?.title || `disabled`} diff --git a/e2e-tests/mdx/src/pages/frontmatter-json.mdx b/e2e-tests/mdx/src/pages/frontmatter-json.mdx new file mode 100644 index 0000000000000..e64f1e0fec826 --- /dev/null +++ b/e2e-tests/mdx/src/pages/frontmatter-json.mdx @@ -0,0 +1,8 @@ +---json +{ "title": "I am parsed", "otherKey": "Some other key" } + +--- + +

A page with JSON frontmatter

+ +{props.pageContext.frontmatter?.title} diff --git a/e2e-tests/mdx/src/pages/frontmatter-yaml.mdx b/e2e-tests/mdx/src/pages/frontmatter-yaml.mdx new file mode 100644 index 0000000000000..baa4ab4363889 --- /dev/null +++ b/e2e-tests/mdx/src/pages/frontmatter-yaml.mdx @@ -0,0 +1,9 @@ +---yaml +title: I am parsed +otherKey: Some other key + +--- + +

A page with YAML frontmatter

+ +{props.pageContext.frontmatter?.title} diff --git a/packages/gatsby-plugin-mdx/loaders/mdx-loader.js b/packages/gatsby-plugin-mdx/loaders/mdx-loader.js index 5309e93009f65..af3c6a30603cb 100644 --- a/packages/gatsby-plugin-mdx/loaders/mdx-loader.js +++ b/packages/gatsby-plugin-mdx/loaders/mdx-loader.js @@ -182,12 +182,9 @@ export const _frontmatter = ${JSON.stringify(data)};` // check needs to happen first. if (!hasDefaultExport(content, options) && !!defaultLayout) { debug(`inserting default layout`, defaultLayout) - const { content: contentWithoutFrontmatter, matter } = grayMatter( - content, - options - ) + const { content: contentWithoutFrontmatter } = grayMatter(content, options) - code = `${matter ? matter : ``} + code = ` import DefaultLayout from "${slash(defaultLayout)}"