Skip to content
This repository was archived by the owner on Apr 3, 2024. It is now read-only.

Commit 36a0c2c

Browse files
Add allowExpressions option (#244)
PR-URL: #244
1 parent 48a9952 commit 36a0c2c

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-0
lines changed

src/agent/config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ module.exports = {
3737
*/
3838
description: null,
3939

40+
/**
41+
* @property {boolean} Whether or not it is permitted to evaluate expressions.
42+
* Locals and arguments are not displayed and watch expressions and conditions
43+
* are dissallowed when this is `false`.
44+
* @memberof DebugAgentConfig
45+
* @default
46+
*/
47+
allowExpressions: false,
48+
4049
// FIXME(ofrobots): today we prioritize GAE_MODULE_NAME/GAE_MODULE_VERSION
4150
// over the user specified config. We should reverse that.
4251
/**

src/agent/debuglet.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ var pjson = require('../../package.json');
3838

3939
var assert = require('assert');
4040

41+
var ALLOW_EXPRESSIONS_MESSAGE = 'Expressions and conditions are not allowed' +
42+
' by default. Please set the allowExpressions configuration option to true';
4143
var NODE_VERSION_MESSAGE = 'Node.js version not supported. Node.js 5.2.0 and ' +
4244
' versions older than 0.12 are not supported.';
4345
var BREAKPOINT_ACTION_MESSAGE = 'The only currently supported breakpoint actions' +
@@ -539,6 +541,15 @@ Debuglet.prototype.removeBreakpoint_ = function(breakpoint) {
539541
Debuglet.prototype.addBreakpoint_ = function(breakpoint, cb) {
540542
var that = this;
541543

544+
if (!that.config_.allowExpressions &&
545+
(breakpoint.condition || breakpoint.expressions)) {
546+
that.logger_.error(ALLOW_EXPRESSIONS_MESSAGE);
547+
breakpoint.status = new StatusMessage(StatusMessage.UNSPECIFIED,
548+
ALLOW_EXPRESSIONS_MESSAGE, true);
549+
setImmediate(function() { cb(ALLOW_EXPRESSIONS_MESSAGE); });
550+
return;
551+
}
552+
542553
if (semver.satisfies(process.version, '5.2 || <0.12')) {
543554
var message = NODE_VERSION_MESSAGE;
544555
that.logger_.error(message);

src/agent/state.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ StateResolver.prototype.isPathInNodeModulesDirectory_ = function(path) {
290290
StateResolver.prototype.resolveFrame_ = function(frame, underFrameCap) {
291291
var args = [];
292292
var locals = [];
293+
// Locals and arguments are safe to collect even when `config.allowExpressions=false`
294+
// since we properly avoid inspecting interceptors and getters by default.
293295
if (!underFrameCap) {
294296
args.push({
295297
name: 'arguments_not_available',

test/test-debuglet.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
var _ = require('lodash');
1919
var assert = require('assert');
2020
var DEFAULT_CONFIG = require('../src/agent/config.js');
21+
DEFAULT_CONFIG.allowExpressions = true;
2122
var Debuglet = require('../src/agent/debuglet.js');
2223
var extend = require('extend');
2324

@@ -526,6 +527,88 @@ describe('Debuglet', function() {
526527
debuglet.start();
527528
});
528529

530+
it('should reject breakpoints with conditions when allowExpressions=false',
531+
function(done) {
532+
this.timeout(2000);
533+
var debug = require('../src/debug.js')(
534+
{projectId: 'fake-project', credentials: fakeCredentials});
535+
var debuglet = new Debuglet(debug, defaultConfig);
536+
debuglet.config_.allowExpressions = false;
537+
538+
var scope = nock(API)
539+
.post(REGISTER_PATH)
540+
.reply(200, {debuggee: {id: DEBUGGEE_ID}})
541+
.get(BPS_PATH + '?success_on_timeout=true')
542+
.reply(200, {breakpoints: [{
543+
id: 'test',
544+
action: 'CAPTURE',
545+
condition: 'x === 5',
546+
location: {path: 'fixtures/foo.js', line: 2}
547+
}]})
548+
.put(BPS_PATH + '/test',
549+
function(body) {
550+
var status = body.breakpoint.status;
551+
var hasCorrectDescription = status.description.format.indexOf(
552+
'Expressions and conditions are not allowed by default.') === 0;
553+
return status.isError && hasCorrectDescription;
554+
})
555+
.reply(200);
556+
557+
debuglet.once('registered', function reg(id) {
558+
assert.equal(id, DEBUGGEE_ID);
559+
setTimeout(function() {
560+
assert.ok(!debuglet.activeBreakpointMap_.test);
561+
debuglet.stop();
562+
debuglet.config_.allowExpressions = true;
563+
scope.done();
564+
done();
565+
}, 1000);
566+
});
567+
568+
debuglet.start();
569+
});
570+
571+
it('should reject breakpoints with expressions when allowExpressions=false',
572+
function(done) {
573+
this.timeout(2000);
574+
var debug = require('../src/debug.js')(
575+
{projectId: 'fake-project', credentials: fakeCredentials});
576+
var debuglet = new Debuglet(debug, defaultConfig);
577+
debuglet.config_.allowExpressions = false;
578+
579+
var scope = nock(API)
580+
.post(REGISTER_PATH)
581+
.reply(200, {debuggee: {id: DEBUGGEE_ID}})
582+
.get(BPS_PATH + '?success_on_timeout=true')
583+
.reply(200, {breakpoints: [{
584+
id: 'test',
585+
action: 'CAPTURE',
586+
expressions: ['x'],
587+
location: {path: 'fixtures/foo.js', line: 2}
588+
}]})
589+
.put(BPS_PATH + '/test',
590+
function(body) {
591+
var status = body.breakpoint.status;
592+
var hasCorrectDescription = status.description.format.indexOf(
593+
'Expressions and conditions are not allowed by default.') === 0;
594+
return status.isError && hasCorrectDescription;
595+
})
596+
.reply(200);
597+
598+
debuglet.once('registered', function reg(id) {
599+
assert.equal(id, DEBUGGEE_ID);
600+
setTimeout(function() {
601+
assert.ok(!debuglet.activeBreakpointMap_.test);
602+
debuglet.stop();
603+
debuglet.config_.allowExpressions = true;
604+
scope.done();
605+
done();
606+
}, 1000);
607+
});
608+
609+
debuglet.start();
610+
});
611+
529612
it('should re-fetch breakpoints on error', function(done) {
530613
this.timeout(6000);
531614

0 commit comments

Comments
 (0)