Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catch invalid env variable 1621 #1626

Merged
merged 16 commits into from
Sep 23, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions cli/__snapshots__/cli_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,30 @@ exports['cli -v no binary version 1'] = `
Cypress package version: 1.2.3
Cypress binary version: not installed
`

exports['cli CYPRESS_ENV allows staging environment 1'] = `
code: 0
stderr:
-------

-------

`

exports['cli CYPRESS_ENV catches environment "foo" 1'] = `
code: 11
stderr:
-------
We have detected unknown or unsupported CYPRESS_ENV value
jennifer-shehane marked this conversation as resolved.
Show resolved Hide resolved

Please unset CYPRESS_ENV variable and run Cypress again
----------

foo
----------

Platform: xxx
Cypress Version: 1.2.3
-------

`
3 changes: 2 additions & 1 deletion cli/__snapshots__/errors_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ exports['errors individual has the following errors 1'] = [
"versionMismatch",
"unexpected",
"failedDownload",
"failedUnzip"
"failedUnzip",
"invalidCypressEnv"
]

exports['errors .errors.formErrorText returns fully formed text message 1'] = `
Expand Down
2 changes: 1 addition & 1 deletion cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ switch (args.exec) {

break
default:
// export our node module interface
debug('exporting Cypress module interface')
module.exports = require('./lib/cypress')
}
6 changes: 6 additions & 0 deletions cli/lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { oneLine } = require('common-tags')
const debug = require('debug')('cypress:cli')
const util = require('./util')
const logger = require('./logger')
const errors = require('./errors')

const coerceFalse = (arg) => {
return arg !== 'false'
Expand Down Expand Up @@ -77,6 +78,11 @@ module.exports = {
args = process.argv
}

if (!util.isValidCypressEnvValue(process.env.CYPRESS_ENV)) {
debug('invalid CYPRESS_ENV value', process.env.CYPRESS_ENV)
return errors.exitWithError(errors.errors.invalidCypressEnv)(process.env.CYPRESS_ENV)
}

const program = new commander.Command()

// bug in commaner not printing name
Expand Down
22 changes: 22 additions & 0 deletions cli/lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ const unexpected = {
`,
}

const invalidCypressEnv = {
description: 'We have detected unknown or unsupported CYPRESS_ENV value',
solution: 'Please unset CYPRESS_ENV variable and run Cypress again',
exitCode: 11,
}

const getOsVersion = () => {
if (os.platform() === 'linux') {
return getos()
Expand Down Expand Up @@ -171,8 +177,23 @@ const throwFormErrorText = (info) => (msg) => {
.then(raise)
}

/**
* Forms full error message with error and OS details, prints to the error output
* and then exits the process.
* @param {ErrorInformation} info Error information {description, solution}
* @example return exitWithError(errors.invalidCypressEnv)('foo')
*/
const exitWithError = (info) => (msg) => {
return formErrorText(info, msg).then((text) => {
// eslint-disable-next-line no-console
console.error(text)
process.exit(info.exitCode || 1)
})
}

module.exports = {
raise,
exitWithError,
// formError,
formErrorText,
throwFormErrorText,
Expand All @@ -185,5 +206,6 @@ module.exports = {
unexpected,
failedDownload,
failedUnzip,
invalidCypressEnv,
},
}
20 changes: 20 additions & 0 deletions cli/lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,29 @@ function stdoutLineMatches (expectedLine, stdout) {
return lines.some(lineMatches)
}

/**
* Confirms if given value is a valid CYPRESS_ENV value. Undefined values
* are valid, because the system can set the default one.
*
* @param {string} value
* @example util.isValidCypressEnvValue(process.env.CYPRESS_ENV)
*/
function isValidCypressEnvValue (value) {
if (_.isUndefined(value)) {
// will get default value
return true
}

// names of config environments, see "packages/server/config/app.yml"
const names = ['development', 'test', 'staging', 'production']
return _.includes(names, value)
}

const util = {
normalizeModuleOptions,

isValidCypressEnvValue,

isCi () {
return isCi
},
Expand Down
2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"clear-module": "^2.1.0",
"dependency-check": "^2.8.0",
"dtslint": "0.2.0",
"execa-wrap": "1.1.0",
"execa-wrap": "1.4.0",
"nock": "^9.0.9",
"shelljs": "0.7.8",
"sinon": "3.2.1",
Expand Down
47 changes: 47 additions & 0 deletions cli/test/lib/cli_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const verify = require(`${lib}/tasks/verify`)
const install = require(`${lib}/tasks/install`)
const snapshot = require('snap-shot-it')
const execa = require('execa-wrap')
const os = require('os')

describe('cli', function () {
require('mocha-banner').register()
Expand Down Expand Up @@ -42,6 +43,52 @@ describe('cli', function () {
)
})

context('CYPRESS_ENV', () => {
/**
* Replaces line "Platform: ..." with "Platform: xxx"
* @param {string} s
*/
const replacePlatform = (s) =>
s.replace(/Platform: .+/, 'Platform: xxx')

/**
* Replaces line "Cypress Version: ..." with "Cypress Version: 1.2.3"
* @param {string} s
*/
const replaceCypressVersion = (s) =>
s.replace(/Cypress Version: .+/, 'Cypress Version: 1.2.3')

const sanitizePlatform = (text) =>
text.split(os.eol)
.map(replacePlatform)
.map(replaceCypressVersion)
.join(os.eol)

it('allows staging environment', () => {
const options = {
env: {
CYPRESS_ENV: 'staging',
},
// we are only interested in the exit code
filter: ['code', 'stderr'],
}
return execa('bin/cypress', ['help'], options).then(snapshot)
})

it('catches environment "foo"', () => {
const options = {
env: {
CYPRESS_ENV: 'foo',
},
// we are only interested in the exit code
filter: ['code', 'stderr'],
}
return execa('bin/cypress', ['help'], options)
.then(sanitizePlatform)
.then(snapshot)
})
})

context('cypress version', function () {
it('reports package version', function (done) {
this.sandbox.stub(util, 'pkgVersion').returns('1.2.3')
Expand Down
10 changes: 10 additions & 0 deletions packages/server/lib/config.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ validate = (file) ->
module.exports = {
getConfigKeys: -> configKeys

isValidCypressEnvValue: (value) ->
# names of config environments, see "config/app.yml"
names = ["development", "test", "staging", "production"]
_.includes(names, value)

whitelist: (obj = {}) ->
_.pick(obj, configKeys)

Expand Down Expand Up @@ -236,7 +241,12 @@ module.exports = {
## split out our own app wide env from user env variables
## and delete envFile
config.env = @parseEnv(config, options.env, resolved)

config.cypressEnv = process.env["CYPRESS_ENV"]
log("using CYPRESS_ENV %s", config.cypressEnv)
if not @isValidCypressEnvValue(config.cypressEnv)
errors.throw("INVALID_CYPRESS_ENV", config.cypressEnv)

delete config.envFile

if hosts = config.hosts
Expand Down
8 changes: 8 additions & 0 deletions packages/server/lib/errors.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,14 @@ API = {

We looked but did not find a #{chalk.blue('cypress.json')} file in this folder: #{chalk.blue(arg1)}
"""
when "INVALID_CYPRESS_ENV"
"""
We have detected unknown or unsupported CYPRESS_ENV value

#{chalk.yellow(arg1)}

Please do not modify CYPRESS_ENV value.
"""

get: (type, arg1, arg2) ->
msg = @getMsgByType(type, arg1, arg2)
Expand Down
30 changes: 26 additions & 4 deletions packages/server/test/unit/config_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ require("../spec_helper")
_ = require("lodash")
path = require("path")
R = require("ramda")
config = require("#{root}lib/config")
configUtil = require("#{root}lib/util/config")
scaffold = require("#{root}lib/scaffold")
settings = require("#{root}lib/util/settings")
config = require("#{root}lib/config")
errors = require("#{root}lib/errors")
configUtil = require("#{root}lib/util/config")
scaffold = require("#{root}lib/scaffold")
settings = require("#{root}lib/util/settings")

describe "lib/config", ->
beforeEach ->
Expand All @@ -17,6 +18,27 @@ describe "lib/config", ->
afterEach ->
process.env = @env

context "environment name check", ->
it "throws an error for unknown CYPRESS_ENV", ->
@sandbox.stub(errors, "throw").withArgs("INVALID_CYPRESS_ENV", "foo-bar")
process.env.CYPRESS_ENV = "foo-bar"
cfg = {
projectRoot: "/foo/bar/"
}
options = {}
config.mergeDefaults(cfg, options)
expect(errors.throw).have.been.calledOnce

it "allows known CYPRESS_ENV", ->
@sandbox.stub(errors, "throw")
process.env.CYPRESS_ENV = "test"
cfg = {
projectRoot: "/foo/bar/"
}
options = {}
config.mergeDefaults(cfg, options)
expect(errors.throw).not.to.be.called

context ".get", ->
beforeEach ->
@projectPath = "/_test-output/path/to/project"
Expand Down