Skip to content

Commit 199a0dc

Browse files
authored
feat: redact x-addon-sso header and response from /sso endpoints from debug logs (#68)
* feat: redact x-addon-sso header * feat: redact response from endpoints ending in /sso from debug logs * fix: fix tests and add chalk dependency * test: test fix
1 parent 7735c47 commit 199a0dc

File tree

5 files changed

+110
-19
lines changed

5 files changed

+110
-19
lines changed

.DS_Store

8 KB
Binary file not shown.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
"author": "Heroku",
66
"bugs": "https://github.com/heroku/http-call/issues",
77
"dependencies": {
8+
"chalk": "^4.1.2",
89
"content-type": "^1.0.5",
910
"debug": "^4.4.0",
1011
"is-retry-allowed": "^2.2.0",
1112
"is-stream": "^2.0.0",
13+
"sinon": "^20.0.0",
1214
"tunnel-agent": "^0.6.0"
1315
},
1416
"devDependencies": {
@@ -17,11 +19,13 @@
1719
"@types/jest": "^29.5.14",
1820
"@types/nock": "^10.0.3",
1921
"@types/node": "20.14.8",
22+
"@types/sinon": "^17.0.4",
2023
"eslint": "^7.32.0",
2124
"eslint-config-oclif": "^4.0.0",
2225
"eslint-config-oclif-typescript": "^1.0.2",
2326
"jest": "^29.7.0",
2427
"nock": "^11.9.1",
28+
"strip-ansi": "6.0.1",
2529
"ts-jest": "^29.2.5",
2630
"typescript": "4.8.4"
2731
},

src/http.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import * as nock from 'nock'
22
import * as querystring from 'node:querystring'
3+
import * as sinon from 'sinon'
4+
const stripAnsi = require('strip-ansi')
5+
const debug = require('debug')
36

47
// eslint-disable-next-line node/no-missing-import
58
import {Global} from './global'
@@ -335,6 +338,36 @@ describe('HTTP.parseBody()', () => {
335338
})
336339
})
337340

341+
describe('debug logs', () => {
342+
let debugSpy: sinon.SinonSpy
343+
beforeEach(() => {
344+
debugSpy = sinon.spy(debug, 'log')
345+
debug.enable('*')
346+
})
347+
afterEach(() => {
348+
debug.disable('*')
349+
debugSpy.restore()
350+
})
351+
352+
it('redacts authorization header from debug logs', async () => {
353+
api.get('/').reply(200, {message: 'ok'}, {authorization: '1234567890'})
354+
await HTTP.get('https://api.jdxcode.com')
355+
expect(stripAnsi(debugSpy.secondCall.firstArg)).toContain('authorization: \'[REDACTED]\'')
356+
})
357+
358+
it('redacts x-addon-sso header from debug logs', async () => {
359+
api.get('/').reply(200, {message: 'ok'}, {'x-addon-sso': '1234567890'})
360+
await HTTP.get('https://api.jdxcode.com')
361+
expect(stripAnsi(debugSpy.secondCall.firstArg)).toContain('x-addon-sso: \'[REDACTED]\'')
362+
})
363+
364+
it('redacts the response from endpoints ending in /sso from debug logs', async () => {
365+
api.get('/sso').reply(200, {message: 'ok'})
366+
await HTTP.get('https://api.jdxcode.com/sso')
367+
expect(stripAnsi(debugSpy.secondCall.firstArg)).toContain('[REDACTED]')
368+
})
369+
})
370+
338371
describe('HTTP.put()', () => {
339372
test('makes a PUT request', async () => {
340373
api.put('/', {foo: 'bar'}).reply(200, {message: 'ok'})

src/http.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {Global} from './global'
88
const pjson = require('../package.json')
99
const debug = require('debug')('http')
1010
const debugHeaders = require('debug')('http:headers')
11+
const chalk = require('chalk')
1112

1213
interface IErrorWithCode extends Error {
1314
code?: string
@@ -332,24 +333,18 @@ export class HTTP<T> {
332333
throw err
333334
}
334335

335-
private get _chalk(): any {
336-
try {
337-
return require('chalk')
338-
} catch {}
339-
}
340-
341336
private _renderStatus(code: number) {
342337
if (code < 200) return code
343-
if (code < 300) return this._chalk.green(code)
344-
if (code < 400) return this._chalk.bold.cyan(code)
345-
if (code < 500) return this._chalk.bgYellow(code)
346-
if (code < 600) return this._chalk.bgRed(code)
338+
if (code < 300) return chalk.green(code)
339+
if (code < 400) return chalk.bold.cyan(code)
340+
if (code < 500) return chalk.bgYellow(code)
341+
if (code < 600) return chalk.bgRed(code)
347342
return code
348343
}
349344

350345
private _debugRequest() {
351346
if (!debug.enabled) return
352-
const output = [`${this._chalk.bold('→')} ${this._chalk.blue.bold(this.options.method)} ${this._chalk.bold(this.url)}`]
347+
const output = [`${chalk.bold('→')} ${chalk.blue.bold(this.options.method)} ${chalk.bold(this.url)}`]
353348
if (this.options.agent) output.push(` proxy: ${inspect(this.options.agent)}`)
354349
if (debugHeaders.enabled) output.push(this._renderHeaders(this.options.headers))
355350
if (this.options.body) output.push(this.options.body)
@@ -358,23 +353,28 @@ export class HTTP<T> {
358353

359354
private _debugResponse() {
360355
if (!debug.enabled) return
361-
const chalk = require('chalk')
362-
const output = [`${this._chalk.white.bold('←')} ${this._chalk.blue.bold(this.method)} ${this._chalk.bold(this.url)} ${this._renderStatus(this.statusCode)}`]
356+
const output = [`${chalk.white.bold('←')} ${chalk.blue.bold(this.method)} ${chalk.bold(this.url)} ${this._renderStatus(this.statusCode)}`]
363357
if (debugHeaders.enabled) output.push(this._renderHeaders(this.headers))
364-
if (this.body) output.push(inspect(this.body))
358+
if (this.body) {
359+
if (this.options.path?.endsWith('/sso')) {
360+
output.push('[REDACTED]')
361+
} else output.push(inspect(this.body))
362+
}
363+
365364
debug(output.join('\n'))
366365
}
367366

368367
private _renderHeaders(headers: http.IncomingHttpHeaders | http.OutgoingHttpHeaders): string {
369368
headers = {...headers}
370369
if (process.env.HTTP_CALL_REDACT !== '0' && headers.authorization) headers.authorization = '[REDACTED]'
370+
if (process.env.HTTP_CALL_REDACT !== '0' && headers['x-addon-sso']) headers['x-addon-sso'] = '[REDACTED]'
371371
return Object.entries(headers)
372372
.sort(([a], [b]) => {
373373
if (a < b) return -1
374374
if (a > b) return 1
375375
return 0
376376
})
377-
.map(([k, v]) => ` ${this._chalk.dim(k + ':')} ${this._chalk.cyan(inspect(v))}`)
377+
.map(([k, v]) => ` ${chalk.dim(k + ':')} ${chalk.cyan(inspect(v))}`)
378378
.join('\n')
379379
}
380380

yarn.lock

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@
636636
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
637637
integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
638638

639-
"@sinonjs/commons@^3.0.0":
639+
"@sinonjs/commons@^3.0.0", "@sinonjs/commons@^3.0.1":
640640
version "3.0.1"
641641
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd"
642642
integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==
@@ -650,6 +650,22 @@
650650
dependencies:
651651
"@sinonjs/commons" "^3.0.0"
652652

653+
"@sinonjs/fake-timers@^13.0.5":
654+
version "13.0.5"
655+
resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz#36b9dbc21ad5546486ea9173d6bea063eb1717d5"
656+
integrity sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==
657+
dependencies:
658+
"@sinonjs/commons" "^3.0.1"
659+
660+
"@sinonjs/samsam@^8.0.1":
661+
version "8.0.2"
662+
resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-8.0.2.tgz#e4386bf668ff36c95949e55a38dc5f5892fc2689"
663+
integrity sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==
664+
dependencies:
665+
"@sinonjs/commons" "^3.0.1"
666+
lodash.get "^4.4.2"
667+
type-detect "^4.1.0"
668+
653669
"@types/babel__core@^7.1.14":
654670
version "7.20.5"
655671
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
@@ -756,6 +772,18 @@
756772
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901"
757773
integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==
758774

775+
"@types/sinon@^17.0.4":
776+
version "17.0.4"
777+
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-17.0.4.tgz#fd9a3e8e07eea1a3f4a6f82a972c899e5778f369"
778+
integrity sha512-RHnIrhfPO3+tJT0s7cFaXGZvsL4bbR3/k7z3P312qMS4JaS2Tk+KiwiLx1S0rQ56ERj00u1/BtdyVd0FY+Pdew==
779+
dependencies:
780+
"@types/sinonjs__fake-timers" "*"
781+
782+
"@types/sinonjs__fake-timers@*":
783+
version "8.1.5"
784+
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz#5fd3592ff10c1e9695d377020c033116cc2889f2"
785+
integrity sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==
786+
759787
"@types/stack-utils@^2.0.0":
760788
version "2.0.3"
761789
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
@@ -1092,7 +1120,7 @@ chalk@^2.0.0, chalk@^2.4.2:
10921120
escape-string-regexp "^1.0.5"
10931121
supports-color "^5.3.0"
10941122

1095-
chalk@^4.0.0, chalk@^4.0.2:
1123+
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.2:
10961124
version "4.1.2"
10971125
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
10981126
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -1246,6 +1274,11 @@ diff-sequences@^29.6.3:
12461274
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
12471275
integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
12481276

1277+
diff@^7.0.0:
1278+
version "7.0.0"
1279+
resolved "https://registry.yarnpkg.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a"
1280+
integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==
1281+
12491282
dir-glob@^3.0.1:
12501283
version "3.0.1"
12511284
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -2416,6 +2449,11 @@ locate-path@^5.0.0:
24162449
dependencies:
24172450
p-locate "^4.1.0"
24182451

2452+
lodash.get@^4.4.2:
2453+
version "4.4.2"
2454+
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
2455+
integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
2456+
24192457
lodash.memoize@^4.1.2:
24202458
version "4.1.2"
24212459
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -2904,6 +2942,17 @@ signal-exit@^3.0.3, signal-exit@^3.0.7:
29042942
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
29052943
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
29062944

2945+
sinon@^20.0.0:
2946+
version "20.0.0"
2947+
resolved "https://registry.yarnpkg.com/sinon/-/sinon-20.0.0.tgz#4b653468735f7152ba694d05498c2b5d024ab006"
2948+
integrity sha512-+FXOAbdnj94AQIxH0w1v8gzNxkawVvNqE3jUzRLptR71Oykeu2RrQXXl/VQjKay+Qnh73fDt/oDfMo6xMeDQbQ==
2949+
dependencies:
2950+
"@sinonjs/commons" "^3.0.1"
2951+
"@sinonjs/fake-timers" "^13.0.5"
2952+
"@sinonjs/samsam" "^8.0.1"
2953+
diff "^7.0.0"
2954+
supports-color "^7.2.0"
2955+
29072956
sisteransi@^1.0.0:
29082957
version "1.0.2"
29092958
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.2.tgz#ec57d64b6f25c4f26c0e2c7dd23f2d7f12f7e418"
@@ -2991,7 +3040,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
29913040
is-fullwidth-code-point "^3.0.0"
29923041
strip-ansi "^6.0.1"
29933042

2994-
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
3043+
strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
29953044
version "6.0.1"
29963045
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
29973046
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -3020,7 +3069,7 @@ supports-color@^5.3.0:
30203069
dependencies:
30213070
has-flag "^3.0.0"
30223071

3023-
supports-color@^7.1.0:
3072+
supports-color@^7.1.0, supports-color@^7.2.0:
30243073
version "7.2.0"
30253074
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
30263075
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
@@ -3127,6 +3176,11 @@ [email protected]:
31273176
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
31283177
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
31293178

3179+
type-detect@^4.1.0:
3180+
version "4.1.0"
3181+
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c"
3182+
integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==
3183+
31303184
type-fest@^0.20.2:
31313185
version "0.20.2"
31323186
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"

0 commit comments

Comments
 (0)