Skip to content

Commit

Permalink
fix: accommodate logging without colors enabled when redacting
Browse files Browse the repository at this point in the history
  • Loading branch information
Kelly Selden authored and kellyselden committed Aug 28, 2020
1 parent 8ed47b3 commit 0ecb207
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 124 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module.exports = {
'packages/mocha/src/role.js',
'examples/*/tests/**/*-test.js',
'fixtures/global-install/tests/**/*-test.js',
'fixtures/redact-password-test.js',
'fixtures/retries-test.js',
'test/**/*.js',
],
Expand Down
113 changes: 113 additions & 0 deletions fixtures/redact-password-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
'use strict';

const { describe, it, setUpObjectReset } = require('../helpers/mocha');
const { expect } = require('../helpers/chai');
const { setUpWebDriver } = require('../packages/lifecycle/src');
const debug = require('../packages/utils/src/scope-debug');
const sinon = require('sinon');
const Server = require('../helpers/server');

const password = Math.random().toString(36).substr(2);

const passwordMatcher = sinon.match(obj => {
if (typeof obj === 'string') {
return obj.includes(password);
}
for (let key in obj) {
return obj[key].includes(password);
}
});

describe(function() {
setUpWebDriver.call(this, {
shareWebdriver: true,
shouldLogIn: false,
overrides: {
logLevel: process.env.LOG_LEVEL || 'info',
waitforTimeout: 0,
},
});

let rawMethod;

setUpObjectReset(debug);

let server;
let port;

before(async function() {
server = new Server();

port = await server.start();
});

beforeEach(async function() {
if (!debug.enabled) {
// suppress real logging during this test
// if logging is turned off
debug.log = () => {};
}
debug.enabled = true;

rawMethod = sinon.stub(
require('../packages/utils/src/require-before-webdriverio'),
'rawMethod',
);

await this.browser.url(`http://localhost:${port}/redact-password.html`);
});

afterEach(function() {
sinon.restore();
});

after(async function() {
if (server) {
await server.stop();
}
});

it('verifies our expectations are correct of what should be caught', async function() {
await this.browser.setValue('input', password);

expect(rawMethod.withArgs(passwordMatcher)).to.have.callCount(0);
expect(rawMethod.withArgs(sinon.match.any, passwordMatcher)).to.have.callCount(0);
expect(rawMethod.withArgs(sinon.match.any, sinon.match.any, passwordMatcher)).to.have.callCount(2);

expect(await this.browser.getValue('input')).to.equal(password);
});

it('hides any passwords from logs', async function() {
await this.browser.setPassword('input', password);

expect(rawMethod.withArgs(sinon.match.any, sinon.match.any, sinon.match({ text: '[REDACTED]' }))).to.have.been.calledOnce;
expect(rawMethod.withArgs(sinon.match.any, sinon.match.any, sinon.match('[REDACTED]'))).to.have.been.calledOnce;

expect(rawMethod.withArgs(passwordMatcher), 'check for any missed').to.have.callCount(0);
expect(rawMethod.withArgs(sinon.match.any, passwordMatcher), 'check for any missed').to.have.callCount(0);
expect(rawMethod.withArgs(sinon.match.any, sinon.match.any, passwordMatcher), 'check for any missed').to.have.callCount(0);

expect(await this.browser.getValue('input')).to.equal(password);
});

it('also hides empty strings', async function() {
await this.browser.setPassword('input', '');

expect(rawMethod.withArgs(sinon.match.any, sinon.match.any, sinon.match({ text: '[REDACTED]' }))).to.have.been.calledOnce;
expect(rawMethod.withArgs(sinon.match.any, sinon.match.any, sinon.match('[REDACTED]'))).to.have.been.calledOnce;

expect(await this.browser.getValue('input')).to.equal('');
});

it('hides any passwords from error messages', async function() {
let err;
try {
await this.browser.setPassword('.missing', password);
} catch (_err) {
err = _err;
}

expect(err.message).to.contain('setPassword(.missing,[REDACTED])')
.and.not.contain(password, 'check for any missed');
});
});
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"chai-fs": "^2.0.0",
"chai-string": "^1.5.0",
"connect": "^3.7.0",
"cross-env": "^6.0.3",
"eslint": "^6.6.0",
"eslint-config-crowdstrike": "^2.0.0",
"eslint-config-crowdstrike-node": "^2.0.0",
Expand All @@ -42,6 +43,7 @@
"remark-preset-lint-crowdstrike": "^1.0.2",
"renovate-config-standard": "^2.0.0",
"serve-static": "^1.14.1",
"sinon": "^8.0.0",
"sinon-chai": "^3.3.0",
"stoppable": "^1.1.0",
"tmp": "0.2.1"
Expand Down
1 change: 0 additions & 1 deletion packages/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
},
"devDependencies": {
"mocha": "^7.0.1",
"sinon": "^8.0.0",
"tmp": "0.2.1"
}
}
121 changes: 0 additions & 121 deletions packages/browser/test/acceptance/redact-password-test.js

This file was deleted.

8 changes: 6 additions & 2 deletions packages/utils/src/require-before-webdriverio.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const log = require('loglevel');

const replacementText = '[REDACTED]';
const elementSendKeysRegex = /elementSendKeys\("(.+)", ".*"\)/;
// eslint-disable-next-line no-control-regex
const commandRegex = /^(?:\x1b\[35m)?COMMAND(?:\x1b\[39m)?$/;
// eslint-disable-next-line no-control-regex
const dataRegex = /^(?:\x1b\[33m)?DATA(?:\x1b\[39m)?$/;

let replacementCountRemaining;
function resetCounter() {
Expand Down Expand Up @@ -43,11 +47,11 @@ log.methodFactory = function(methodName, level, loggerName) {
if (replacementCountRemaining > 0 && type) {
let wasFound;

if (type === '[35mCOMMAND[39m' && elementSendKeysRegex.test(data)) {
if (commandRegex.test(type) && elementSendKeysRegex.test(data)) {
rawMethod(message, type, data.replace(elementSendKeysRegex, `elementSendKeys("$1", "${replacementText}")`));
wasFound = true;
}
if (type === '[33mDATA[39m' && Object.prototype.hasOwnProperty.call(data, 'text')) {
if (dataRegex.test(type) && Object.prototype.hasOwnProperty.call(data, 'text')) {
rawMethod(message, type, {
...data,
text: replacementText,
Expand Down
26 changes: 26 additions & 0 deletions test/acceptance.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,30 @@ describe(function() {

expect(output).to.include(' 1 passing');
});

it('cross-env FORCE_COLOR=1 mocha fixtures/redact-password-test.js --exit', async function() {
this.timeout(60 * 1000);

let output = await this.run();

expect(output).to.include(' 4 passing');
});

// more permissive log level
it('cross-env LOG_LEVEL=trace mocha fixtures/redact-password-test.js --exit', async function() {
this.timeout(60 * 1000);

let output = await this.run();

expect(output).to.include(' 4 passing');
});

// without colors
it('cross-env FORCE_COLOR=0 mocha fixtures/redact-password-test.js --exit', async function() {
this.timeout(60 * 1000);

let output = await this.run();

expect(output).to.include(' 4 passing');
});
});
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,13 @@ create-error-class@^3.0.1:
dependencies:
capture-stack-trace "^1.0.0"

cross-env@^6.0.3:
version "6.0.3"
resolved "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941"
integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==
dependencies:
cross-spawn "^7.0.0"

cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
Expand Down

0 comments on commit 0ecb207

Please sign in to comment.