Skip to content

Commit ee8991b

Browse files
committed
feat: Add disableLogging option to getManagementToken
1 parent 3a82d43 commit ee8991b

File tree

2 files changed

+80
-15
lines changed

2 files changed

+80
-15
lines changed

src/keys/get-management-token.spec.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ import { Logger } from '../utils'
1414
import { sign } from 'jsonwebtoken'
1515
import { LRUCache } from 'lru-cache'
1616

17+
// Mock the debug logger to spy on it
18+
const mockDebugInstance = {
19+
extend: sinon.stub().returns(sinon.spy()),
20+
}
21+
sinon.stub(require('debug'), 'default').returns(mockDebugInstance)
22+
1723
const PRIVATE_KEY = fs.readFileSync(path.join(__dirname, '..', '..', 'keys', 'key.pem'), 'utf-8')
1824
const APP_ID = 'app_id'
1925
const SPACE_ID = 'space_id'
@@ -29,6 +35,64 @@ const noop = () => {}
2935
const defaultCache: LRUCache<string, string> = new LRUCache({ max: 10 })
3036

3137
describe('getManagementToken', () => {
38+
let loggerSpy: sinon.SinonSpy
39+
40+
beforeEach(() => {
41+
// Reset the spy before each test
42+
loggerSpy = mockDebugInstance.extend() as sinon.SinonSpy
43+
loggerSpy.resetHistory()
44+
// Reset cache as well
45+
defaultCache.clear()
46+
})
47+
48+
it('fetches a token and logs by default', async () => {
49+
const mockToken = 'token'
50+
// Use the real logger creator, but we spy on the debug instance it creates
51+
const { createLogger } = await import('../utils/logger')
52+
const logger = createLogger({ filename: __filename })
53+
const post = sinon.stub()
54+
post.resolves({ statusCode: 201, body: JSON.stringify({ token: mockToken }) })
55+
const httpClient = { post } as unknown as HttpClient
56+
const getManagementTokenFn = createGetManagementToken(logger, httpClient, defaultCache)
57+
58+
const result = await getManagementTokenFn(PRIVATE_KEY, DEFAULT_OPTIONS) // disableLogging is default false
59+
60+
assert.deepStrictEqual(result, mockToken)
61+
assert(
62+
post.calledWith(
63+
`spaces/${SPACE_ID}/environments/${ENVIRONMENT_ID}/app_installations/${APP_ID}/access_tokens`,
64+
sinon.match({ headers: { Authorization: sinon.match.string } }),
65+
),
66+
)
67+
// Assert that the logger spy was called
68+
assert(loggerSpy.called, 'Logger should have been called by default')
69+
})
70+
71+
it('does not log when disableLogging is true', async () => {
72+
const mockToken = 'token-no-log'
73+
const { createLogger } = await import('../utils/logger')
74+
const logger = createLogger({ filename: __filename })
75+
const post = sinon.stub()
76+
post.resolves({ statusCode: 201, body: JSON.stringify({ token: mockToken }) })
77+
const httpClient = { post } as unknown as HttpClient
78+
const getManagementTokenFn = createGetManagementToken(logger, httpClient, defaultCache)
79+
80+
const result = await getManagementTokenFn(PRIVATE_KEY, {
81+
...DEFAULT_OPTIONS,
82+
disableLogging: true,
83+
})
84+
85+
assert.deepStrictEqual(result, mockToken)
86+
assert(
87+
post.calledWith(
88+
`spaces/${SPACE_ID}/environments/${ENVIRONMENT_ID}/app_installations/${APP_ID}/access_tokens`,
89+
sinon.match({ headers: { Authorization: sinon.match.string } }),
90+
),
91+
)
92+
// Assert that the logger spy was NOT called
93+
assert(!loggerSpy.called, 'Logger should not have been called when disableLogging is true')
94+
})
95+
3296
it('fetches a token', async () => {
3397
const mockToken = 'token'
3498
const logger = noop as unknown as Logger

src/keys/get-management-token.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface GetManagementTokenOptions {
1818
keyId?: string
1919
reuseToken?: boolean
2020
host?: string
21+
disableLogging?: boolean
2122
}
2223

2324
let defaultCache: LRUCache<string, string> | undefined
@@ -29,15 +30,15 @@ let defaultCache: LRUCache<string, string> | undefined
2930
const generateOneTimeToken = (
3031
privateKey: string,
3132
{ appId, keyId }: { appId: string; keyId?: string },
32-
{ log }: { log: Logger },
33+
{ log, disableLogging }: { log: Logger; disableLogging: boolean },
3334
): string => {
34-
log('Signing a JWT token with private key')
35+
if (!disableLogging) log('Signing a JWT token with private key')
3536
try {
3637
const baseSignOptions: SignOptions = { algorithm: 'RS256', issuer: appId, expiresIn: '10m' }
3738
const signOptions: SignOptions = keyId ? { ...baseSignOptions, keyid: keyId } : baseSignOptions
3839

3940
const token = sign({}, privateKey, signOptions)
40-
log('Successfully signed token')
41+
if (!disableLogging) log('Successfully signed token')
4142
return token
4243
} catch (e) {
4344
log('Unable to sign token')
@@ -52,11 +53,11 @@ const getTokenFromOneTimeToken = async (
5253
spaceId,
5354
environmentId,
5455
}: { appInstallationId: string; spaceId: string; environmentId: string },
55-
{ log, http }: { log: Logger; http: HttpClient },
56+
{ log, http, disableLogging }: { log: Logger; http: HttpClient; disableLogging: boolean },
5657
): Promise<string> => {
5758
const validateStatusCode = createValidateStatusCode([201])
5859

59-
log(`Requesting CMA Token with given App Token`)
60+
if (!disableLogging) log(`Requesting CMA Token with given App Token`)
6061

6162
const response = await http.post(
6263
`spaces/${spaceId}/environments/${environmentId}/app_installations/${appInstallationId}/access_tokens`,
@@ -70,9 +71,10 @@ const getTokenFromOneTimeToken = async (
7071
},
7172
)
7273

73-
log(
74-
`Successfully retrieved CMA Token for app ${appInstallationId} in space ${spaceId} and environment ${environmentId}`,
75-
)
74+
if (!disableLogging)
75+
log(
76+
`Successfully retrieved CMA Token for app ${appInstallationId} in space ${spaceId} and environment ${environmentId}`,
77+
)
7678

7779
return JSON.parse(response.body).token
7880
}
@@ -91,13 +93,12 @@ export const createGetManagementToken = (
9193
throw new ReferenceError('Invalid privateKey: expected a string representing a private key')
9294
}
9395

94-
if (opts.reuseToken === undefined) {
95-
opts.reuseToken = true
96-
}
96+
const reuseToken = opts.reuseToken ?? true
97+
const disableLogging = opts.disableLogging ?? false
9798

9899
const cacheKey =
99100
opts.appInstallationId + opts.spaceId + opts.environmentId + privateKey.slice(32, 132)
100-
if (opts.reuseToken) {
101+
if (reuseToken) {
101102
const existing = cache.get(cacheKey) as string
102103
if (existing) {
103104
return existing as string
@@ -107,10 +108,10 @@ export const createGetManagementToken = (
107108
const appToken = generateOneTimeToken(
108109
privateKey,
109110
{ appId: opts.appInstallationId, keyId: opts.keyId },
110-
{ log },
111+
{ log, disableLogging },
111112
)
112-
const ott = await getTokenFromOneTimeToken(appToken, opts, { log, http })
113-
if (opts.reuseToken) {
113+
const ott = await getTokenFromOneTimeToken(appToken, opts, { log, http, disableLogging })
114+
if (reuseToken) {
114115
const decoded = decode(ott)
115116
if (decoded && typeof decoded === 'object' && decoded.exp) {
116117
// Internally expire cached tokens a bit earlier to make sure token isn't expired on arrival

0 commit comments

Comments
 (0)