From 139b8f3a5bf60c3ed699238d7ebda6db01e48e7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 22:39:46 +0000 Subject: [PATCH 1/3] Initial plan From ebd21d775512731d946955e49e94ab8e6da603b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 22:55:26 +0000 Subject: [PATCH 2/3] Fix SSL config forwarding: update docs, examples, and add tests for config.requestOptions Fix issue #239 - Users upgrading to Node 18+ encounter SSL errors due to OpenSSL changes. The config.requestOptions mechanism already supports passing agentOptions through to postman-request, but was undocumented. Changes: - Fix README: change broken rpOptions to requestOptions in SOCKS proxy example - Add SSL/TLS configuration section to README with usage examples - Update pass_request_options.js example to show init-time and per-call options - Add 7 unit tests verifying config.requestOptions forwarding for all methods Co-authored-by: aviadhahami <7353632+aviadhahami@users.noreply.github.com> --- README.md | 38 ++++++++- example/pass_request_options.js | 18 ++++- test/unit.js | 136 ++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 44fe4dce..88679f49 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ const SocksProxyAgent = require('socks-proxy-agent'); const agent = new SocksProxyAgent(`socks://127.0.0.1:${socks4Port}`, true); const options = { apiVersion: 'v1', - rpOptions: { + requestOptions: { agent, }, }; @@ -128,6 +128,42 @@ const options = { const vault = require('node-vault')(options); ``` +## Custom SSL/TLS Configuration + +If you encounter SSL errors after upgrading to Node 18+ (e.g., `EPROTO` errors related to +`unsafe legacy renegotiation disabled`), you can pass SSL/TLS options via `requestOptions` +or `rpDefaults` when initializing the client: + +```javascript +const vault = require('node-vault')({ + apiVersion: 'v1', + endpoint: 'https://vault.example.com:8200', + token: 'MY_TOKEN', + requestOptions: { + agentOptions: { + securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT', + }, + }, +}); +``` + +The `requestOptions` object is passed through to the underlying HTTP library +([postman-request](https://www.npmjs.com/package/postman-request)) for every request. You can +use it to configure any supported request option, including `agentOptions`, custom `headers`, +or a custom `agent`. + +You can also pass request options per-call to any method: + +```javascript +vault.read('secret/hello', { + agentOptions: { + securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT', + }, +}); +``` + +See [example/pass_request_options.js](example/pass_request_options.js) for more examples. + [![Backers](https://opencollective.com/node-vault/tiers/backers.svg?avatarHeight=80&width=600)](https://opencollective.com/node-vault/contribute) [examples]: https://github.com/nodevault/node-vault/tree/master/example diff --git a/example/pass_request_options.js b/example/pass_request_options.js index 2c81a248..95166c26 100644 --- a/example/pass_request_options.js +++ b/example/pass_request_options.js @@ -2,9 +2,21 @@ process.env.DEBUG = 'node-vault'; // switch on debug mode -const vault = require('./../src/index')(); +// Pass request options at initialization time. +// These options are forwarded to postman-request for every request. +const vault = require('./../src/index')({ + requestOptions: { + agentOptions: { + cert: 'mycert', + key: 'mykey', + passphrase: 'password', + securityOptions: 'SSL_OP_NO_SSLv3', + }, + }, +}); -const options = { +// You can also pass (or override) request options per-call. +const perCallOptions = { headers: { 'X-HELLO': 'world', }, @@ -16,6 +28,6 @@ const options = { }, }; -vault.help('sys/policy', options) +vault.help('sys/policy', perCallOptions) .then(() => vault.help('sys/mounts')) .catch((err) => console.error(err.message)); diff --git a/test/unit.js b/test/unit.js index 2ac9525b..1ba67384 100644 --- a/test/unit.js +++ b/test/unit.js @@ -295,6 +295,142 @@ describe('node-vault', () => { }); }); + describe('config.requestOptions forwarding', () => { + let requestWithOpts = null; + let vaultWithOpts = null; + + const agentOpts = { + securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT', + }; + + function getURIWithOpts(path) { + return [vaultWithOpts.endpoint, vaultWithOpts.apiVersion, path].join('/'); + } + + function assertRequestWithOpts(thisRequest, params, done) { + return () => { + thisRequest.should.have.calledOnce(); + thisRequest.calledWithMatch(params).should.be.ok(); + return done(); + }; + } + + beforeEach(() => { + requestWithOpts = sinon.stub(); + const resp = sinon.stub(); + resp.statusCode = 200; + + requestWithOpts.returns({ + then(fn) { + return fn(resp); + }, + catch(fn) { + return fn(); + }, + }); + + vaultWithOpts = index({ + endpoint: 'http://localhost:8200', + token: '123', + 'request-promise': { + defaults: () => requestWithOpts, + }, + requestOptions: { + agentOptions: agentOpts, + }, + }); + }); + + it('should forward agentOptions from config.requestOptions in help()', (done) => { + const path = 'sys/policy'; + const params = { + method: 'GET', + uri: `${getURIWithOpts(path)}?help=1`, + agentOptions: agentOpts, + }; + vaultWithOpts.help(path) + .then(assertRequestWithOpts(requestWithOpts, params, done)) + .catch(done); + }); + + it('should forward agentOptions from config.requestOptions in read()', (done) => { + const path = 'secret/hello'; + const params = { + method: 'GET', + uri: getURIWithOpts(path), + agentOptions: agentOpts, + }; + vaultWithOpts.read(path) + .then(assertRequestWithOpts(requestWithOpts, params, done)) + .catch(done); + }); + + it('should forward agentOptions from config.requestOptions in write()', (done) => { + const path = 'secret/hello'; + const params = { + method: 'POST', + uri: getURIWithOpts(path), + agentOptions: agentOpts, + }; + vaultWithOpts.write(path, { value: 'world' }) + .then(assertRequestWithOpts(requestWithOpts, params, done)) + .catch(done); + }); + + it('should forward agentOptions from config.requestOptions in delete()', (done) => { + const path = 'secret/hello'; + const params = { + method: 'DELETE', + uri: getURIWithOpts(path), + agentOptions: agentOpts, + }; + vaultWithOpts.delete(path) + .then(assertRequestWithOpts(requestWithOpts, params, done)) + .catch(done); + }); + + it('should forward agentOptions from config.requestOptions in list()', (done) => { + const path = 'secret/hello'; + const params = { + method: 'LIST', + uri: getURIWithOpts(path), + agentOptions: agentOpts, + }; + vaultWithOpts.list(path) + .then(assertRequestWithOpts(requestWithOpts, params, done)) + .catch(done); + }); + + it('should forward agentOptions from config.requestOptions in generated functions', (done) => { + const name = 'myTestFunction'; + vaultWithOpts.generateFunction(name, { + method: 'GET', + path: '/myroute', + }); + const params = { + agentOptions: agentOpts, + }; + vaultWithOpts[name]() + .then(assertRequestWithOpts(requestWithOpts, params, done)) + .catch(done); + }); + + it('should allow per-call requestOptions to override config.requestOptions', (done) => { + const path = 'secret/hello'; + const overrideOpts = { + securityOptions: 'SSL_OP_NO_SSLv3', + }; + const params = { + method: 'GET', + uri: getURIWithOpts(path), + agentOptions: overrideOpts, + }; + vaultWithOpts.read(path, { agentOptions: overrideOpts }) + .then(assertRequestWithOpts(requestWithOpts, params, done)) + .catch(done); + }); + }); + describe('unwrap(options)', () => { it('should return original response', (done) => { const path = 'sys/wrapping/unwrap'; From c9f651b0bb6e1e2c21c856f61f4deaffb6215312 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 22:57:19 +0000 Subject: [PATCH 3/3] Update example placeholders to be more explicit Co-authored-by: aviadhahami <7353632+aviadhahami@users.noreply.github.com> --- example/pass_request_options.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/example/pass_request_options.js b/example/pass_request_options.js index 95166c26..c48b1a12 100644 --- a/example/pass_request_options.js +++ b/example/pass_request_options.js @@ -7,9 +7,9 @@ process.env.DEBUG = 'node-vault'; // switch on debug mode const vault = require('./../src/index')({ requestOptions: { agentOptions: { - cert: 'mycert', - key: 'mykey', - passphrase: 'password', + cert: '', + key: '', + passphrase: '', securityOptions: 'SSL_OP_NO_SSLv3', }, }, @@ -21,9 +21,9 @@ const perCallOptions = { 'X-HELLO': 'world', }, agentOptions: { - cert: 'mycert', - key: 'mykey', - passphrase: 'password', + cert: '', + key: '', + passphrase: '', securityOptions: 'SSL_OP_NO_SSLv3', }, };