Skip to content

Commit

Permalink
feat: add support for vault secrets in scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
Pranav Joglekar committed Jul 11, 2024
1 parent 565c803 commit dfc6d6f
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ The following section outlines the API available inside sandbox scripts
- pm.environment
- pm.collectionVariables
- pm.test
- pm.vaultSecrets

#### pre-request script specials

Expand Down
12 changes: 11 additions & 1 deletion lib/sandbox/execution.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const _ = require('lodash'),
sdk = require('postman-collection'),

PROPERTY = {
REQUEST: 'request',
SCRIPT: 'script',
Expand Down Expand Up @@ -41,6 +40,17 @@ class Execution {
this[variableScope].enableTracking(trackingOptions);
});

this.vaultSecrets = sdk.VariableScope.isVariableScope(context.vaultSecrets) ?
context.vaultSecrets : new sdk.VariableScope({
prefix: 'vault:',
...(_.isArray(context.vaultSecrets) || sdk.VariableList.isVariableList(context.values) ? {
values: context.vaultSecrets
} : {
...context.vaultSecrets
})
});
this.vaultSecrets.enableTracking(trackingOptions);

if (options.initializeExecution) {
const { request, response } = options.initializeExecution(this.target, context) || {};

Expand Down
6 changes: 6 additions & 0 deletions lib/sandbox/pmapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function Postman (execution, onRequest, onSkipRequest, onAssertion, cookieStore,
execution._variables.addLayer(execution.environment.values);
execution._variables.addLayer(execution.collectionVariables.values);
execution._variables.addLayer(execution.globals.values);
execution._variables.addLayer(execution.vaultSecrets.values);

execution.cookies && (execution.cookies.jar = function () {
return new PostmanCookieJar(cookieStore);
Expand Down Expand Up @@ -124,6 +125,11 @@ function Postman (execution, onRequest, onSkipRequest, onAssertion, cookieStore,
requestId: execution.legacy._itemId
}),

/**
* @type {VariableScope}
*/
vault: execution.vaultSecrets,

/**
* @type {VariableScope}
*/
Expand Down
8 changes: 8 additions & 0 deletions test/unit/pm-variables-tracking.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ describe('pm api variables', function () {
assert.equal(pm.collectionVariables.mutations.count(), 0);
pm.collectionVariables.set('foo', 'foo');
assert.equal(pm.collectionVariables.mutations.count(), 1);
assert.equal(pm.vault.mutations.count(), 0);
pm.vault.set('foo', 'foo');
assert.equal(pm.vault.mutations.count(), 1);
`, done);
});
});
Expand All @@ -41,6 +45,7 @@ describe('pm api variables', function () {
pm.environment.set('foo', 'environment');
pm.globals.set('foo', 'global');
pm.collectionVariables.set('foo', 'collectionVariables');
pm.vault.set('foo', 'vaultVariable');
`, function (err, result) {
if (err) {
return done(err);
Expand All @@ -58,6 +63,9 @@ describe('pm api variables', function () {
expect(result.collectionVariables.mutations).to.be.ok;
expect(new sdk.MutationTracker(result.collectionVariables.mutations).count()).to.equal(1);

expect(result.vaultSecrets.mutations).to.be.ok;
expect(new sdk.MutationTracker(result.vaultSecrets.mutations).count()).to.equal(1);

done();
});
});
Expand Down
28 changes: 24 additions & 4 deletions test/unit/pm-variables.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ describe('pm.variables', function () {

describe('.set', function () {
before(function (done) {
var globalVarList = new sdk.VariableList(null, { key: 'key-1', value: 'value-1' }),
var vaultSecretList = new sdk.VariableList(null, { key: 'vault:key-0', value: 'value-0' }),
globalVarList = new sdk.VariableList(null, { key: 'key-1', value: 'value-1' }),
collectionVarList = new sdk.VariableList(null, { key: 'key-2', value: 'value-2' }),
envVarList = new sdk.VariableList(null, { key: 'key-3', value: 'value-3' }),
contextData = { 'key-4': 'value-4' },
localVarList = new sdk.VariableList(null, { key: 'key-5', value: 'value-5' });

ctx.execute(`
pm.variables.set("vault:key-0", "modified");
pm.variables.set("key-1", "modified");
pm.variables.set("key-2", "modified");
pm.variables.set("key-3", "modified");
Expand All @@ -46,6 +48,7 @@ describe('pm.variables', function () {
`, {
timeout: 200,
context: {
vaultSecrets: new sdk.VariableScope(vaultSecretList),
globals: new sdk.VariableScope(globalVarList),
collectionVariables: new sdk.VariableScope(collectionVarList),
environment: new sdk.VariableScope(envVarList),
Expand All @@ -64,6 +67,7 @@ describe('pm.variables', function () {
it('should return the modified variables in the result', function () {
expect(executionResults).to.deep.nested.include({ '_variables.values': [
{ type: 'any', value: 'modified', key: 'key-5' },
{ type: 'any', value: 'modified', key: 'vault:key-0' },
{ type: 'any', value: 'modified', key: 'key-1' },
{ type: 'any', value: 'modified', key: 'key-2' },
{ type: 'any', value: 'modified', key: 'key-3' },
Expand All @@ -74,6 +78,9 @@ describe('pm.variables', function () {

it('should not modify the globals, envrironment, collection and data variables', function () {
expect(executionResults).to.deep.nested.include({
'vaultSecrets.values': [
{ type: 'any', key: 'vault:key-0', value: 'value-0' }
],
'globals.values': [
{ type: 'any', value: 'value-1', key: 'key-1' }
],
Expand Down Expand Up @@ -128,7 +135,12 @@ describe('pm.variables', function () {

describe('.get', function () {
it('should honour the precendence', function (done) {
var globalVarList = new sdk.VariableList(null, [
var vaultSecretList = new sdk.VariableList(null, [
{ key: 'vault:key-0', value: 'value-0' },
{ key: 'vault:key-1', value: 'value-0' }
]),
globalVarList = new sdk.VariableList(null, [
{ key: 'vault:key-1', value: 'value-1' },
{ key: 'key-1', value: 'value-1' },
{ key: 'key-2', value: 'value-1' },
{ key: 'key-3', value: 'value-1' },
Expand Down Expand Up @@ -165,11 +177,14 @@ describe('pm.variables', function () {
'key-2': 'value-2',
'key-3': 'value-3',
'key-4': 'value-4',
'key-5': 'value-5'
'key-5': 'value-5',
'vault:key-0': 'value-0',
'vault:key-1': 'value-1'
});
`, {
timeout: 200,
context: {
vaultSecrets: new sdk.VariableScope(vaultSecretList),
globals: new sdk.VariableScope(globalVarList),
collectionVariables: new sdk.VariableScope(collectionVarList),
environment: new sdk.VariableScope(envVarList),
Expand All @@ -186,14 +201,16 @@ describe('pm.variables', function () {
});

it('should return appropriate variables', function (done) {
var globalVarList = new sdk.VariableList(null, { key: 'key-1', value: 'value-1' }),
var vaultSecretList = new sdk.VariableList(null, { key: 'vault:key-0', value: 'value-0' }),
globalVarList = new sdk.VariableList(null, { key: 'key-1', value: 'value-1' }),
collectionVarList = new sdk.VariableList(null, { key: 'key-2', value: 'value-2' }),
envVarList = new sdk.VariableList(null, { key: 'key-3', value: 'value-3' }),
contextData = { 'key-4': 'value-4' },
localVarList = new sdk.VariableList(null, { key: 'key-5', value: 'value-5' });

ctx.execute(`
var assert = require('assert');
assert.strictEqual(pm.variables.get('vault:key-0'), 'value-0');
assert.strictEqual(pm.variables.get('key-1'), 'value-1');
assert.strictEqual(pm.variables.get('key-2'), 'value-2');
assert.strictEqual(pm.variables.get('key-3'), 'value-3');
Expand All @@ -203,6 +220,7 @@ describe('pm.variables', function () {
`, {
timeout: 200,
context: {
vaultSecrets: new sdk.VariableScope(vaultSecretList),
globals: new sdk.VariableScope(globalVarList),
collectionVariables: new sdk.VariableScope(collectionVarList),
environment: new sdk.VariableScope(envVarList),
Expand All @@ -221,6 +239,7 @@ describe('pm.variables', function () {
it('should reinitialize the variables when same sandbox instance is used again', function (done) {
ctx.execute(`
var assert = require('assert');
assert.strictEqual(pm.variables.get('vault:key-0'), undefined);
assert.strictEqual(pm.variables.get('key-1'), undefined);
assert.strictEqual(pm.variables.get('key-2'), undefined);
assert.strictEqual(pm.variables.get('key-3'), undefined);
Expand All @@ -234,6 +253,7 @@ describe('pm.variables', function () {
if (err) { return done(err); }

expect(execution).to.deep.nested.include({
'vaultSecrets.values': [],
'globals.values': [],
'_variables.values': [],
'collectionVariables.values': [],
Expand Down
80 changes: 80 additions & 0 deletions test/unit/sandbox-libraries/pm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ describe('sandbox library - pm api', function () {
value: 2.9,
type: 'number'
}],
vaultSecrets: [{
key: 'vault:var1',
value: 'one-vault',
type: 'string'
}, {
key: 'vault:var2',
value: 'two-vault',
type: 'string'
}],
data: {
var1: 'one-data'
}
Expand Down Expand Up @@ -265,6 +274,77 @@ describe('sandbox library - pm api', function () {
});
});

describe('vaultSecrets', function () {
it('should be defined as VariableScope', function (done) {
context.execute(`
var assert = require('assert'),
VariableScope = require('postman-collection').VariableScope;
assert.strictEqual(VariableScope.isVariableScope(pm.vault), true);
`, { context: sampleContextData }, done);
});

it('should be a readonly property', function (done) {
context.execute(`
var assert = require('assert'),
_vaultSecrets;
_vaultSecrets = pm.vault;
pm.vault = [];
assert.strictEqual(pm.vault, _vaultSecrets, 'property stays unchanged');
`, { context: sampleContextData }, done);
});

it('should forward vaultSecrets forwarded during execution', function (done) {
context.execute(`
var assert = require('assert');
assert.strictEqual(pm.vault.get('var1'), 'one-vault');
assert.strictEqual(pm.vault.get('var2'), 'two-vault');
`, { context: sampleContextData }, done);
});

it('pm.vault.toObject must return a pojo', function (done) {
context.execute(`
var assert = require('assert');
assert.strictEqual(_.isPlainObject(pm.vault.toObject()), true);
assert.deepEqual(pm.vault.toObject(), {
'vault:var1': 'one-vault',
'vault:var2': 'two-vault'
});
`, { context: sampleContextData }, done);
});
it('pm.variables.toObject must contain vaultSecrets', function (done) {
context.execute(`
var assert = require('assert');
assert.strictEqual(_.isPlainObject(pm.variables.toObject()), true);
assert.deepEqual(pm.variables.toObject(), {
'vault:var1': 'one-vault',
'vault:var2': 'two-vault',
'var1': 'one-data',
'var2': 2.5
});
`, { context: sampleContextData }, done);
});
it('should propagate updated vault secrets from inside sandbox', function (done) {
context.execute(`
var assert = require('assert');
pm.vault.set('var1', 'one-one-vault');
assert.strictEqual(pm.vault.get('var1'), 'one-one-vault');
`, { context: sampleContextData }, function (err, exec) {
expect(err).to.be.null;
expect(exec).to.be.ok;
expect(exec).to.deep.nested.include({ 'vaultSecrets.values': [
{ type: 'string', value: 'one-one-vault', key: 'vault:var1' },
{ type: 'string', value: 'two-vault', key: 'vault:var2' }
] });
done();
});
});
});

describe('request', function () {
it('should be defined as sdk Request object', function (done) {
context.execute(`
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ declare class Postman {
globals: VariableScope;
environment: VariableScope;
collectionVariables: VariableScope;
vault: VariableScope;
variables: VariableScope;
/**
* The iterationData object contains data from the data file provided during a collection run.
Expand Down
1 change: 1 addition & 0 deletions types/sandbox/prerequest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ declare class Postman {
globals: import("postman-collection").VariableScope;
environment: import("postman-collection").VariableScope;
collectionVariables: import("postman-collection").VariableScope;
vault: import("postman-collection").VariableScope;
variables: import("postman-collection").VariableScope;
/**
* The iterationData object contains data from the data file provided during a collection run.
Expand Down
1 change: 1 addition & 0 deletions types/sandbox/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ declare class Postman {
globals: import("postman-collection").VariableScope;
environment: import("postman-collection").VariableScope;
collectionVariables: import("postman-collection").VariableScope;
vault: import("postman-collection").VariableScope;
variables: import("postman-collection").VariableScope;
/**
* The iterationData object contains data from the data file provided during a collection run.
Expand Down

0 comments on commit dfc6d6f

Please sign in to comment.