diff --git a/src/Job.js b/src/Job.js index d3a175b..2f395ec 100644 --- a/src/Job.js +++ b/src/Job.js @@ -65,7 +65,7 @@ module.exports = function (grunt) { var requestParams = { method: 'POST', url: ['https://saucelabs.com/rest/v1', this.user, 'js-tests'].join('/'), - auth: { user: this.user, pass: this.key }, + auth: { user: this.user, pass: this.key() }, json: { platforms: [this.platform], url: this.url, @@ -141,7 +141,7 @@ module.exports = function (grunt) { .makeRequest({ method: 'POST', url: ['https://saucelabs.com/rest/v1', me.user, 'js-tests/status'].join('/'), - auth: { user: me.user, pass: me.key }, + auth: { user: me.user, pass: me.key() }, json: { 'js tests': [me.taskId] } }) .then(function (body) { @@ -182,7 +182,7 @@ module.exports = function (grunt) { return utils.makeRequest({ method: 'PUT', url: ['https://saucelabs.com/rest/v1', this.user, 'jobs', this.id, 'stop'].join('/'), - auth: { user: this.user, pass: this.key } + auth: { user: this.user, pass: this.key() } }); }; @@ -196,7 +196,7 @@ module.exports = function (grunt) { return utils.makeRequest({ method: 'DELETE', url: ['https://saucelabs.com/rest/v1', this.user, 'jobs', this.id].join('/'), - auth: { user: this.user, pass: this.key } + auth: { user: this.user, pass: this.key() } }); }; diff --git a/tasks/saucelabs.js b/tasks/saucelabs.js index cfa96c9..389c03f 100644 --- a/tasks/saucelabs.js +++ b/tasks/saucelabs.js @@ -77,7 +77,7 @@ module.exports = function (grunt) { type: 'tunnelOpen' }); - tunnel = new SauceTunnel(arg.username, arg.key, arg.identifier, true, ['-P', '0'].concat(arg.tunnelArgs)); + tunnel = new SauceTunnel(arg.username, arg.key(), arg.identifier, true, ['-P', '0'].concat(arg.tunnelArgs)); ['write', 'writeln', 'error', 'ok', 'debug'].forEach(function (method) { tunnel.on('log:' + method, function (text) { @@ -161,7 +161,6 @@ module.exports = function (grunt) { var defaults = { username: process.env.SAUCE_USERNAME, - key: process.env.SAUCE_ACCESS_KEY, tunneled: true, identifier: Math.floor((new Date()).getTime() / 1000 - 1230768000).toString(), pollInterval: 1000 * 2, @@ -173,6 +172,27 @@ module.exports = function (grunt) { maxRetries: 0 }; + // Grunt will print the options hash to console.log when run in verbose + // mode. This can cause credential leaks per issue #203. This block will allow + // assignments so it can integrate with Grunt's APIs, but it will always + // return the getter as a function so that the 'toString' and 'toJSON' can be + // overidden. + var key = process.env.SAUCE_ACCESS_KEY; + Object.defineProperty(defaults, 'key', { + enumerable: true, + configurable: false, + writeable: true, + set: function (newKey) { + key = newKey; + }, + get: function () { + var get = function () { return key; }; + get.toString = function () { return key ? "[hidden]" : undefined; }; + get.toJSON = get.toString; + return get; + } + }); + grunt.registerMultiTask('saucelabs-jasmine', 'Run Jasmine test cases using Sauce Labs browsers', function () { var done = this.async(); var arg = this.options(defaults);