From 9efdc9d0b7d5b19aa54a51bd6c454415969ffbb6 Mon Sep 17 00:00:00 2001 From: Saksham Date: Mon, 28 Oct 2024 15:57:38 +0530 Subject: [PATCH 1/4] Fix domain regex to match doimains with or without port (#1480) --- lib/runner/util.js | 2 +- test/integration/sanity/vaultSecrets.test.js | 81 ++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/lib/runner/util.js b/lib/runner/util.js index 471a8b35b..9ee4573bb 100644 --- a/lib/runner/util.js +++ b/lib/runner/util.js @@ -201,7 +201,7 @@ module.exports = { const url = new Url(domain); // @note URL path is ignored - return `${url.protocol || 'https'}://${url.getRemote()}/*`; + return `${url.protocol || 'https'}://${url.getRemote()}:*/*`; })); }); diff --git a/test/integration/sanity/vaultSecrets.test.js b/test/integration/sanity/vaultSecrets.test.js index 6687d69bc..f6319f2a7 100644 --- a/test/integration/sanity/vaultSecrets.test.js +++ b/test/integration/sanity/vaultSecrets.test.js @@ -705,6 +705,87 @@ describe('vaultSecrets', function () { }); }); + describe('should resolve secrets when port is part of url', function () { + var testrun; + + before(function (done) { + this.run({ + vaultSecrets: { + id: 'vault', + prefix: 'vault:', + _allowScriptAccess: true, + values: [ + { + key: 'vault:var1', + value: 'basic-auth', + _domains: ['https://postman-echo.com'] + }, + { + key: 'vault:var2', + value: 'postman', + _domains: ['https://postman-echo.com'] + }, + { + key: 'vault:var3', + value: 'password' + } + ] + }, + collection: { + item: [{ + event: [ + { + listen: 'prerequest', + script: { + exec: 'pm.vault.set(\'var4\', \'http://postman-echo.com\')' + } + } + ], + request: { + url: 'https://postman-echo.com:80/{{vault:var1}}', + method: 'GET', + auth: { + type: 'basic', + basic: [ + { key: 'username', value: '{{vault:var2}}' }, + { key: 'password', value: '{{vault:var3}}' } + ] + } + } + }] + } + }, function (err, results) { + testrun = results; + done(err); + }); + }); + + it('should have completed the run', function () { + expect(testrun).to.be.ok; + expect(testrun.done.getCall(0).args[0]).to.be.null; + expect(testrun).to.nested.include({ + 'done.calledOnce': true, + 'start.calledOnce': true + }); + }); + + it('should handle protocol for a resolved domain', function () { + var url = testrun.request.getCall(0).args[3].url.toString(); + + expect(url).to.equal('https://postman-echo.com:80/basic-auth'); + }); + + it('should resolve vault secrets in auth', function () { + var request = testrun.response.getCall(0).args[3], + auth = request.auth.parameters().toObject(); + + expect(auth).to.deep.include({ + username: 'postman', + password: 'password' + }); + }); + }); + describe('scripts', function () { describe('should be able to get vault secrets using pm.vault.get', function () { var testrun; From ec6c13051889287de465a0e3982b1e084cbe00e6 Mon Sep 17 00:00:00 2001 From: Saksham Date: Mon, 28 Oct 2024 15:59:14 +0530 Subject: [PATCH 2/4] Add support for lazily fetching vault access status (#1478) * feat: Refactor vault access handling in event command * modified logic and test cases * change _allowScriptAccess in tests to be function * Add support for lazily fetching vault access status --------- Co-authored-by: Appurva Murawat --- CHANGELOG.yaml | 4 + lib/runner/extensions/event.command.js | 31 ++- .../sanity/variable-changes.test.js | 2 +- test/integration/sanity/vaultSecrets.test.js | 178 +++++++++++++++++- 4 files changed, 199 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml index f06408add..195c0cc97 100644 --- a/CHANGELOG.yaml +++ b/CHANGELOG.yaml @@ -1,3 +1,7 @@ +unreleased: + new features: + - GH-1478 Added support for lazily fetching vault access status + 7.42.0: date: 2024-09-04 new features: diff --git a/lib/runner/extensions/event.command.js b/lib/runner/extensions/event.command.js index 1b61378e1..5ccd36279 100644 --- a/lib/runner/extensions/event.command.js +++ b/lib/runner/extensions/event.command.js @@ -243,16 +243,12 @@ module.exports = { packageResolver = _.get(this, 'options.script.packageResolver'), vaultSecrets = payload.context.vaultSecrets, - allowVaultAccess = _.get(vaultSecrets, '_.allowScriptAccess'), + // Do not assign any initial value here as it will be used + // to determine if the vault access check was done or not + hasVaultAccess, events; - // Explicitly enable tracking for vault secrets here as this will - // not be sent to sandbox who otherwise takes care of mutation tracking - if (allowVaultAccess) { - vaultSecrets.enableTracking({ autoCompact: true }); - } - // @todo: find a better place to code this so that event is not aware of such options if (abortOnFailure) { abortOnError = true; @@ -398,12 +394,23 @@ module.exports = { } }.bind(this)); - this.host.on(EXECUTION_VAULT_BASE + executionId, function (id, cmd, ...args) { + this.host.on(EXECUTION_VAULT_BASE + executionId, async function (id, cmd, ...args) { + if (hasVaultAccess === undefined) { + try { + // eslint-disable-next-line require-atomic-updates + hasVaultAccess = Boolean(await vaultSecrets?._?.allowScriptAccess(item.id)); + } + catch (_) { + // eslint-disable-next-line require-atomic-updates + hasVaultAccess = false; + } + } + // Ensure error is string // TODO identify why error objects are not being serialized correctly const dispatch = (e, r) => { this.host.dispatch(EXECUTION_VAULT_BASE + executionId, id, e, r); }; - if (!allowVaultAccess) { + if (!hasVaultAccess) { return dispatch('Vault access denied'); } @@ -411,6 +418,10 @@ module.exports = { return dispatch(`Invalid vault command: ${cmd}`); } + // Explicitly enable tracking for vault secrets here as this will + // not be sent to sandbox who otherwise takes care of mutation tracking + vaultSecrets.enableTracking({ autoCompact: true }); + dispatch(null, vaultSecrets[cmd](...args)); }.bind(this)); @@ -556,7 +567,7 @@ module.exports = { result && result.request && (result.request = new sdk.Request(result.request)); // vault secrets are not sent to sandbox, thus using the scope from run context. - if (allowVaultAccess && vaultSecrets) { + if (hasVaultAccess && vaultSecrets) { result.vaultSecrets = vaultSecrets; // Prevent mutations from being carry-forwarded to subsequent events diff --git a/test/integration/sanity/variable-changes.test.js b/test/integration/sanity/variable-changes.test.js index f7488512a..7aaa720ef 100644 --- a/test/integration/sanity/variable-changes.test.js +++ b/test/integration/sanity/variable-changes.test.js @@ -9,7 +9,7 @@ describe('variable changes', function () { requester: { followRedirects: false }, vaultSecrets: { id: 'vault', - _allowScriptAccess: true, + _allowScriptAccess: function () { return true; }, values: [ { key: 'vault:key5', value: 'vault-value-5', enabled: true }, { key: 'vault:key6', value: 'vault-value-6', enabled: true } diff --git a/test/integration/sanity/vaultSecrets.test.js b/test/integration/sanity/vaultSecrets.test.js index f6319f2a7..0bb949475 100644 --- a/test/integration/sanity/vaultSecrets.test.js +++ b/test/integration/sanity/vaultSecrets.test.js @@ -619,7 +619,7 @@ describe('vaultSecrets', function () { vaultSecrets: { id: 'vault', prefix: 'vault:', - _allowScriptAccess: true, + _allowScriptAccess: function () { return true; }, values: [ { key: 'vault:var1', @@ -795,7 +795,7 @@ describe('vaultSecrets', function () { vaultSecrets: { id: 'vault', prefix: 'vault:', - _allowScriptAccess: true, + _allowScriptAccess: function () { return true; }, values: [ { key: 'vault:var1', @@ -847,7 +847,7 @@ describe('vaultSecrets', function () { vaultSecrets: { id: 'vault', prefix: 'vault:', - _allowScriptAccess: true, + _allowScriptAccess: function () { return true; }, values: [ { key: 'vault:var1', @@ -900,7 +900,7 @@ describe('vaultSecrets', function () { vaultSecrets: { id: 'vault', prefix: 'vault:', - _allowScriptAccess: true, + _allowScriptAccess: function () { return true; }, values: [ { key: 'vault:var1', @@ -957,7 +957,7 @@ describe('vaultSecrets', function () { vaultSecrets: { id: 'vault', prefix: 'vault:', - _allowScriptAccess: true, + _allowScriptAccess: function () { return true; }, values: [ { key: 'vault:var1', @@ -1073,5 +1073,173 @@ describe('vaultSecrets', function () { expect(prerequest.vaultSecrets).to.deep.equal(undefined); }); }); + + describe('should handle _allowScriptAccess as a function', function () { + var testrun; + + before(function (done) { + this.run({ + vaultSecrets: { + id: 'vault', + prefix: 'vault:', + _allowScriptAccess: function (itemId) { + return itemId === 'item1'; + }, + values: [ + { + key: 'vault:var1', + value: 'value1' + } + ] + }, + collection: { + item: [{ + id: 'item1', + event: [{ + listen: 'prerequest', + script: { + exec: ` + const v = await pm.vault.get('var1'); + console.log(v); + ` + } + }], + request: 'https://postman-echo.com/get' + }, { + id: 'item2', + event: [{ + listen: 'prerequest', + script: { + exec: ` + try { + const v = await pm.vault.get('var1'); + console.log(v); + } catch (error) { + console.error(error.message); + } + ` + } + }], + request: 'https://postman-echo.com/get' + }] + } + }, function (err, results) { + testrun = results; + done(err); + }); + }); + + it('should allow vault access for item1', function () { + var prConsoleArgs = testrun.console.getCall(0).args.slice(2); + + expect(prConsoleArgs).to.deep.equal(['value1']); + }); + + it('should deny vault access for item2', function () { + var prConsoleArgs = testrun.console.getCall(1).args.slice(2); + + expect(prConsoleArgs).to.deep.equal(['Vault access denied']); + }); + }); + + describe('should fail if _allowScriptAccess is not a function', function () { + var testrun; + + before(function (done) { + this.run({ + vaultSecrets: { + id: 'vault', + prefix: 'vault:', + _allowScriptAccess: true, + values: [ + { + key: 'vault:var1', + value: 'value1' + } + ] + }, + collection: { + item: { + event: [{ + listen: 'prerequest', + script: { + exec: ` + try { + const v = await pm.vault.get('var1'); + console.log('Vault value:', v); + } catch (error) { + console.error('Vault error:', error.message); + } + ` + } + }], + request: 'https://postman-echo.com/get' + } + } + }, function (err, results) { + testrun = results; + done(err); + }); + }); + + it('should deny vault access when _allowScriptAccess is not a function', function () { + expect(testrun.console.called).to.be.true; + + var consoleArgs = testrun.console.getCall(0).args.slice(2); + + expect(consoleArgs[0]).to.equal('Vault error:'); + expect(consoleArgs[1]).to.equal('Vault access denied'); + }); + }); + + describe('should handle when _allowScriptAccess function throws', function () { + var testrun; + + before(function (done) { + this.run({ + vaultSecrets: { + id: 'vault', + prefix: 'vault:', + _allowScriptAccess: function () { throw new Error('Custom error'); }, + values: [ + { + key: 'vault:var1', + value: 'value1' + } + ] + }, + collection: { + item: { + event: [{ + listen: 'prerequest', + script: { + exec: ` + try { + const v = await pm.vault.get('var1'); + console.log('Vault value:', v); + } catch (error) { + console.error('Vault error:', error.message); + } + ` + } + }], + request: 'https://postman-echo.com/get' + } + } + }, function (err, results) { + testrun = results; + done(err); + }); + }); + + it('should deny vault access when _allowScriptAccess function throws', function () { + expect(testrun.console.called).to.be.true; + + var consoleArgs = testrun.console.getCall(0).args.slice(2); + + expect(consoleArgs[0]).to.equal('Vault error:'); + expect(consoleArgs[1]).to.equal('Vault access denied'); + }); + }); }); }); From e5b3f69bf8564e9ab23e9b3aff0414e97a20722e Mon Sep 17 00:00:00 2001 From: Appurva Murawat Date: Wed, 30 Oct 2024 12:14:09 +0530 Subject: [PATCH 3/4] Update changelog --- CHANGELOG.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml index 195c0cc97..9e4f4b609 100644 --- a/CHANGELOG.yaml +++ b/CHANGELOG.yaml @@ -1,6 +1,8 @@ unreleased: new features: - GH-1478 Added support for lazily fetching vault access status + fixed bugs: + - GH-1480 Fixed a bug where vault domain matching did not work with port in URL 7.42.0: date: 2024-09-04 From f21b6547ffbc3646ddafb0841b435d36ac3da0e2 Mon Sep 17 00:00:00 2001 From: Appurva Murawat Date: Wed, 30 Oct 2024 14:02:12 +0530 Subject: [PATCH 4/4] Release v7.43.0 --- CHANGELOG.yaml | 7 +++++-- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml index 9e4f4b609..53933f362 100644 --- a/CHANGELOG.yaml +++ b/CHANGELOG.yaml @@ -1,8 +1,11 @@ -unreleased: +7.43.0: + date: 2024-10-30 new features: - GH-1478 Added support for lazily fetching vault access status fixed bugs: - - GH-1480 Fixed a bug where vault domain matching did not work with port in URL + - >- + GH-1480 Fixed a bug where vault domain matching did not work with port in + URL 7.42.0: date: 2024-09-04 diff --git a/package-lock.json b/package-lock.json index 52cc11a98..17f9d53d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "postman-runtime", - "version": "7.42.0", + "version": "7.43.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "postman-runtime", - "version": "7.42.0", + "version": "7.43.0", "license": "Apache-2.0", "dependencies": { "@postman/tough-cookie": "4.1.3-postman.1", diff --git a/package.json b/package.json index ecaaa120e..e182d0081 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postman-runtime", - "version": "7.42.0", + "version": "7.43.0", "description": "Underlying library of executing Postman Collections", "author": "Postman Inc.", "license": "Apache-2.0",