Skip to content

Commit

Permalink
fix: avoid leaking defined env vars when trying to access not defined…
Browse files Browse the repository at this point in the history
… env vars (#10030)

* fix: avoid leaking defined env vars when trying to access not defined env vars

* test: add some testing for env var usage and leaking

* add some comments to .env.production - it normally shouldn't be commited to repo
  • Loading branch information
pieh committed Nov 19, 2018
1 parent 769932b commit 8061e3b
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 3 deletions.
5 changes: 5 additions & 0 deletions e2e-tests/production-runtime/.env.production
@@ -0,0 +1,5 @@
# This file is commited to repo only to validate that env vars are available
# to use in frontend and don't leak if not used (secrets used in Node).
# You should NOT commit `.env` files to your repository for production sites.
EXISTING_VAR=foo bar
VERY_SECRET_VAR=it's a secret
32 changes: 32 additions & 0 deletions e2e-tests/production-runtime/__tests__/env-vars.js
@@ -0,0 +1,32 @@
const { exec } = require(`child_process`)

const grepJSFilesFor = str =>
new Promise(resolve => {
const grep = exec(`grep -r "${str}" ./public/*.js`)

grep.stdout.on(`data`, () => {
resolve(true)
return
})

grep.on(`close`, () => {
resolve(false)
return
})
})

const checkLeakedEnvVar = async () => {
const isLeaked =
(await grepJSFilesFor(`VERY_SECRET_VAR`)) ||
(await grepJSFilesFor(`it's a secret`))

if (isLeaked) {
console.error(`Error: VERY_SECRET_VAR found in bundle`)
process.exit(1)
} else {
console.log(`Success: VERY_SECRET_VAR not found in bundle`)
process.exit(0)
}
}

checkLeakedEnvVar()
Expand Up @@ -71,4 +71,12 @@ describe(`Production build tests`, () => {
.getTestElement(`404`)
.should(`exist`)
})

it(`Uses env vars`, () => {
cy.visit(`/env-vars`).waitForAPI(`onRouteUpdate`)

cy.getTestElement(`process.env`).contains(`{}`)
cy.getTestElement(`process.env.EXISTING_VAR`).contains(`"foo bar"`)
cy.getTestElement(`process.env.NOT_EXISTING_VAR`).should(`be.empty`)
})
})
3 changes: 2 additions & 1 deletion e2e-tests/production-runtime/package.json
Expand Up @@ -21,7 +21,8 @@
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write '**/*.js'",
"test": "npm run build && npm run start-server-and-test",
"test": "npm run build && npm run start-server-and-test && npm run test-env-vars",
"test-env-vars": " node __tests__/env-vars.js",
"start-server-and-test": "start-server-and-test serve http://localhost:9000 cy:run",
"serve": "gatsby serve",
"cy:open": "cypress open",
Expand Down
29 changes: 29 additions & 0 deletions e2e-tests/production-runtime/src/pages/env-vars.js
@@ -0,0 +1,29 @@
import React from 'react'

import Layout from '../components/layout'

const UseEnv = ({ heading, envVar }) => (
<React.Fragment>
<h2>{heading}</h2>
<pre>
<code data-testid={heading}>{JSON.stringify(envVar)}</code>
</pre>
</React.Fragment>
)

const SecondPage = () => (
<Layout>
<h1>Using env vars</h1>
<UseEnv heading="process.env" envVar={process.env} />
<UseEnv
heading="process.env.EXISTING_VAR"
envVar={process.env.EXISTING_VAR}
/>
<UseEnv
heading="process.env.NOT_EXISTING_VAR"
envVar={process.env.NOT_EXISTING_VAR}
/>
</Layout>
)

export default SecondPage
14 changes: 12 additions & 2 deletions packages/gatsby/src/utils/webpack.config.js
Expand Up @@ -67,7 +67,17 @@ module.exports = async (
envObject.PUBLIC_DIR = JSON.stringify(`${process.cwd()}/public`)
envObject.BUILD_STAGE = JSON.stringify(stage)

return Object.assign(envObject, gatsbyVarObject)
const mergedEnvVars = Object.assign(envObject, gatsbyVarObject)

return Object.keys(mergedEnvVars).reduce(
(acc, key) => {
acc[`process.env.${key}`] = mergedEnvVars[key]
return acc
},
{
"process.env": JSON.stringify({}),
}
)
}

function getHmrPath() {
Expand Down Expand Up @@ -172,7 +182,7 @@ module.exports = async (
// Add a few global variables. Set NODE_ENV to production (enables
// optimizations for React) and what the link prefix is (__PATH_PREFIX__).
plugins.define({
"process.env": processEnv(stage, `development`),
...processEnv(stage, `development`),
__PATH_PREFIX__: JSON.stringify(
program.prefixPaths ? store.getState().config.pathPrefix : ``
),
Expand Down

0 comments on commit 8061e3b

Please sign in to comment.