Skip to content

Commit 209fa58

Browse files
committed
Merge branch 'release/7.49.0'
2 parents 6a8f806 + a80d08a commit 209fa58

File tree

7 files changed

+298
-15
lines changed

7 files changed

+298
-15
lines changed

CHANGELOG.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
7.49.0:
2+
date: 2025-10-16
3+
new features:
4+
- GH-1532 Add support for logging SSL session keys to a file
5+
chores:
6+
- Updated dependencies
7+
18
7.48.0:
29
date: 2025-09-25
310
new features:

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,10 @@ runner.run(collection, {
165165

166166
// The max depth or number of requests a request can invoke via `pm.execution.runRequest`
167167
// in its pre-request and post-response scripts
168-
maxInvokableNestedRequests: 5
168+
maxInvokableNestedRequests: 5,
169+
170+
// Enable logging SSL session keys (only supported on Node, ignored in the browser)
171+
sslKeyLogFile: '/path/to/keylogfile',
169172
},
170173

171174
// Options specific to the script execution
@@ -234,7 +237,7 @@ runner.run(collection, {
234237

235238
// *note* Not implemented yet.
236239
// In the future, this will be used to read certificates from the OS keychain.
237-
systemCertificate: function() {}
240+
systemCertificate: function() {},
238241
}, function (err, run) {
239242
console.log('Created a new Run!');
240243

lib/requester/core.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,8 @@ module.exports = {
512512
options.ciphers = protocolProfileBehavior.tlsCipherSelection.join(':');
513513
}
514514

515+
options.sslKeyLogFile = defaultOpts.sslKeyLogFile;
516+
515517
if (typeof defaultOpts.maxResponseSize === 'number') {
516518
options.maxResponseSize = defaultOpts.maxResponseSize;
517519
}

lib/requester/requester-pool.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ RequesterPool = function (options, callback) {
3838
removeRefererHeaderOnRedirect: _.get(options, 'requester.removeRefererHeaderOnRedirect'),
3939
ignoreProxyEnvironmentVariables: _.get(options, 'ignoreProxyEnvironmentVariables'),
4040
network: _.get(options, 'network', {}),
41-
maxHeaderSize: _.get(options, 'requester.maxHeaderSize', 131072) // 128KB
41+
maxHeaderSize: _.get(options, 'requester.maxHeaderSize', 131072), // 128KB
42+
sslKeyLogFile: _.get(options, 'requester.sslKeyLogFile')
4243
});
4344

4445
// create a cookie jar if one is not provided

package-lock.json

Lines changed: 9 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postman-runtime",
3-
"version": "7.48.0",
3+
"version": "7.49.0",
44
"description": "Underlying library of executing Postman Collections",
55
"author": "Postman Inc.",
66
"license": "Apache-2.0",
@@ -55,7 +55,7 @@
5555
"node-oauth1": "1.3.0",
5656
"performance-now": "2.1.0",
5757
"postman-collection": "5.2.0",
58-
"postman-request": "2.88.1-postman.43",
58+
"postman-request": "2.88.1-postman.45",
5959
"postman-sandbox": "6.2.1",
6060
"postman-url-encoder": "3.0.8",
6161
"serialised-error": "1.1.3",
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
var expect = require('chai').expect;
2+
var fs = require('fs');
3+
4+
5+
(typeof window === 'undefined' ? describe : describe.skip)('Requester Spec: sslKeyLogFile', function () {
6+
var tmp,
7+
path,
8+
testrun,
9+
tmpDir,
10+
sslKeyLogFilePath;
11+
12+
before(function () {
13+
tmp = require('tmp');
14+
path = require('path');
15+
});
16+
17+
describe('with sslKeyLogFile', function () {
18+
before(function (done) {
19+
tmpDir = tmp.dirSync({ unsafeCleanup: true });
20+
sslKeyLogFilePath = path.join(tmpDir.name, 'ssl-keylog.txt');
21+
22+
23+
this.run({
24+
requester: {
25+
strictSSL: false,
26+
sslKeyLogFile: sslKeyLogFilePath
27+
},
28+
collection: {
29+
item: [{
30+
request: global.servers.https
31+
}]
32+
}
33+
}, function (err, results) {
34+
testrun = results;
35+
done(err);
36+
});
37+
});
38+
after(function () {
39+
// Clean up temporary directory
40+
if (tmpDir) {
41+
tmpDir.removeCallback();
42+
}
43+
});
44+
45+
it('should complete the run', function () {
46+
expect(testrun).to.be.ok;
47+
expect(testrun).to.nested.include({
48+
'done.calledOnce': true,
49+
'start.calledOnce': true,
50+
'request.calledOnce': true
51+
});
52+
});
53+
54+
it('should write SSL key log data to the specified file', function () {
55+
// Check that the file exists
56+
expect(fs.existsSync(sslKeyLogFilePath)).to.be.true;
57+
58+
// Read the file contents
59+
const fileContents = fs.readFileSync(sslKeyLogFilePath, 'utf8');
60+
61+
// Verify the file has content (SSL key log entries)
62+
expect(fileContents).to.be.a('string');
63+
expect(fileContents.length).to.be.greaterThan(0);
64+
65+
// SSL key log format should contain CLIENT_RANDOM or other SSL key log entries
66+
// The format is typically lines like: "CLIENT_RANDOM <hex> <hex>"
67+
expect(fileContents).to.match(/CLIENT_/);
68+
});
69+
});
70+
71+
describe('with sslKeyLogFile and non-empty file', function () {
72+
before(function (done) {
73+
tmpDir = tmp.dirSync({ unsafeCleanup: true });
74+
sslKeyLogFilePath = path.join(tmpDir.name, 'ssl-keylog.txt');
75+
76+
// Write some content to the file
77+
fs.writeFileSync(sslKeyLogFilePath, '1234567890');
78+
79+
this.run({
80+
requester: {
81+
strictSSL: false,
82+
sslKeyLogFile: sslKeyLogFilePath
83+
},
84+
collection: {
85+
item: [{
86+
request: global.servers.https
87+
}]
88+
}
89+
}, function (err, results) {
90+
testrun = results;
91+
done(err);
92+
});
93+
});
94+
95+
after(function () {
96+
// Clean up temporary directory
97+
if (tmpDir) {
98+
tmpDir.removeCallback();
99+
}
100+
});
101+
102+
it('should complete the run', function () {
103+
expect(testrun).to.be.ok;
104+
expect(testrun).to.nested.include({
105+
'done.calledOnce': true,
106+
'start.calledOnce': true,
107+
'request.calledOnce': true
108+
});
109+
});
110+
it('should append to the existing SSL key log data in the specified file', function () {
111+
// Check that the file exists
112+
expect(fs.existsSync(sslKeyLogFilePath)).to.be.true;
113+
114+
// Read the file contents
115+
const fileContents = fs.readFileSync(sslKeyLogFilePath, 'utf8');
116+
117+
// Verify the file has content (SSL key log entries)
118+
expect(fileContents).to.be.a('string');
119+
expect(fileContents.length).to.be.greaterThan(0);
120+
121+
// Verify the file contains the existing content
122+
expect(fileContents).to.include('1234567890');
123+
124+
// Verify the file contains the new content
125+
expect(fileContents).to.include('CLIENT_HANDSHAKE_TRAFFIC_SECRET');
126+
});
127+
});
128+
129+
describe('without sslKeyLogFile', function () {
130+
before(function (done) {
131+
tmpDir = tmp.dirSync({ unsafeCleanup: true });
132+
sslKeyLogFilePath = path.join(tmpDir.name, 'ssl-keylog.txt');
133+
134+
this.run({
135+
requester: {
136+
strictSSL: false
137+
},
138+
collection: {
139+
item: [{
140+
request: global.servers.https
141+
}]
142+
}
143+
}, function (err, results) {
144+
testrun = results;
145+
done(err);
146+
});
147+
});
148+
149+
after(function () {
150+
// Clean up temporary directory
151+
if (tmpDir) {
152+
tmpDir.removeCallback();
153+
}
154+
});
155+
156+
it('should complete the run', function () {
157+
expect(testrun).to.be.ok;
158+
expect(testrun).to.nested.include({
159+
'done.calledOnce': true,
160+
'start.calledOnce': true,
161+
'request.calledOnce': true
162+
});
163+
});
164+
165+
it('should not have any SSL key log data in the file', function () {
166+
// Check that the file does not exist
167+
expect(fs.existsSync(sslKeyLogFilePath)).to.be.false;
168+
});
169+
});
170+
171+
describe('with invalid sslKeyLogFile path', function () {
172+
before(function (done) {
173+
tmpDir = tmp.dirSync({ unsafeCleanup: true });
174+
sslKeyLogFilePath = path.join(tmpDir.name, 'ssl-keylog.txt');
175+
176+
this.run({
177+
requester: {
178+
strictSSL: false,
179+
sslKeyLogFile: '/invalid/path/that/does/not/exist/ssl-keylog.txt'
180+
},
181+
collection: {
182+
item: [{
183+
request: global.servers.https
184+
}]
185+
}
186+
}, function (err, results) {
187+
testrun = results;
188+
done(err);
189+
});
190+
});
191+
192+
after(function () {
193+
// Clean up temporary directory
194+
if (tmpDir) {
195+
tmpDir.removeCallback();
196+
}
197+
});
198+
199+
it('should complete the run despite invalid path', function () {
200+
expect(testrun).to.be.ok;
201+
expect(testrun).to.nested.include({
202+
'done.calledOnce': true,
203+
'start.calledOnce': true,
204+
'request.calledOnce': true
205+
});
206+
});
207+
it('should not have any SSL key log data in the file', function () {
208+
// Check that the file does not exist
209+
expect(fs.existsSync(sslKeyLogFilePath)).to.be.false;
210+
});
211+
});
212+
213+
describe('with multiple HTTPS requests', function () {
214+
before(function (done) {
215+
tmpDir = tmp.dirSync({ unsafeCleanup: true });
216+
sslKeyLogFilePath = path.join(tmpDir.name, 'ssl-keylog.txt');
217+
218+
this.run({
219+
requester: {
220+
strictSSL: false,
221+
sslKeyLogFile: sslKeyLogFilePath
222+
},
223+
collection: {
224+
item: [
225+
{
226+
request: global.servers.https
227+
},
228+
{
229+
request: global.servers.https
230+
}
231+
]
232+
}
233+
}, function (err, results) {
234+
testrun = results;
235+
done(err);
236+
});
237+
});
238+
239+
after(function () {
240+
// Clean up temporary directory
241+
if (tmpDir) {
242+
tmpDir.removeCallback();
243+
}
244+
});
245+
246+
it('should complete the run', function () {
247+
expect(testrun).to.be.ok;
248+
expect(testrun).to.nested.include({
249+
'done.calledOnce': true,
250+
'start.calledOnce': true
251+
});
252+
expect(testrun.request.callCount).to.equal(2);
253+
});
254+
255+
it('should write SSL key log data from all requests to the same file', function () {
256+
// Check that the file exists
257+
expect(fs.existsSync(sslKeyLogFilePath)).to.be.true;
258+
259+
// Read the file contents
260+
const fileContents = fs.readFileSync(sslKeyLogFilePath, 'utf8');
261+
262+
// Verify the file has content
263+
expect(fileContents).to.be.a('string');
264+
expect(fileContents.length).to.be.greaterThan(0);
265+
266+
// Should contain SSL key log entries
267+
expect(fileContents).to.match(/CLIENT_/);
268+
});
269+
});
270+
});
271+

0 commit comments

Comments
 (0)