Merge pull request #2229 from actions/copilot/extend-user-agent-http-requests
Extend user-agent with orchestration ID and add default user-agent
This commit is contained in:
@@ -21,7 +21,10 @@ describe('basics', () => {
|
|||||||
_http = new httpm.HttpClient('http-client-tests')
|
_http = new httpm.HttpClient('http-client-tests')
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {})
|
afterEach(() => {
|
||||||
|
// Clean up environment variable to prevent test pollution
|
||||||
|
delete process.env['ACTIONS_ORCHESTRATION_ID']
|
||||||
|
})
|
||||||
|
|
||||||
it('constructs', () => {
|
it('constructs', () => {
|
||||||
const http: httpm.HttpClient = new httpm.HttpClient('thttp-client-tests')
|
const http: httpm.HttpClient = new httpm.HttpClient('thttp-client-tests')
|
||||||
@@ -60,7 +63,7 @@ describe('basics', () => {
|
|||||||
const body: string = await res.readBody()
|
const body: string = await res.readBody()
|
||||||
const obj = JSON.parse(body)
|
const obj = JSON.parse(body)
|
||||||
expect(obj.url).toBe('https://postman-echo.com/get')
|
expect(obj.url).toBe('https://postman-echo.com/get')
|
||||||
expect(obj.headers['user-agent']).toBeFalsy()
|
expect(obj.headers['user-agent']).toBe('actions/http-client')
|
||||||
})
|
})
|
||||||
|
|
||||||
/* TODO write a mock rather then relying on a third party
|
/* TODO write a mock rather then relying on a third party
|
||||||
@@ -374,4 +377,66 @@ describe('basics', () => {
|
|||||||
httpm.MediaTypes.ApplicationJson
|
httpm.MediaTypes.ApplicationJson
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('appends orchestration ID to user-agent when ACTIONS_ORCHESTRATION_ID is set', async () => {
|
||||||
|
const orchId = 'test-orch-id-12345'
|
||||||
|
process.env['ACTIONS_ORCHESTRATION_ID'] = orchId
|
||||||
|
|
||||||
|
const http: httpm.HttpClient = new httpm.HttpClient('http-client-tests')
|
||||||
|
const res: httpm.HttpClientResponse = await http.get(
|
||||||
|
'https://postman-echo.com/get'
|
||||||
|
)
|
||||||
|
expect(res.message.statusCode).toBe(200)
|
||||||
|
const body: string = await res.readBody()
|
||||||
|
const obj = JSON.parse(body)
|
||||||
|
expect(obj.headers['user-agent']).toBe(
|
||||||
|
`http-client-tests actions_orchestration_id/${orchId}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sanitizes invalid characters in orchestration ID', async () => {
|
||||||
|
const orchId = 'test (with) special/chars'
|
||||||
|
process.env['ACTIONS_ORCHESTRATION_ID'] = orchId
|
||||||
|
|
||||||
|
const http: httpm.HttpClient = new httpm.HttpClient('http-client-tests')
|
||||||
|
const res: httpm.HttpClientResponse = await http.get(
|
||||||
|
'https://postman-echo.com/get'
|
||||||
|
)
|
||||||
|
expect(res.message.statusCode).toBe(200)
|
||||||
|
const body: string = await res.readBody()
|
||||||
|
const obj = JSON.parse(body)
|
||||||
|
// Spaces, parentheses, and slashes should be replaced with underscores
|
||||||
|
expect(obj.headers['user-agent']).toBe(
|
||||||
|
'http-client-tests actions_orchestration_id/test__with__special_chars'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not modify user-agent when ACTIONS_ORCHESTRATION_ID is not set', async () => {
|
||||||
|
delete process.env['ACTIONS_ORCHESTRATION_ID']
|
||||||
|
|
||||||
|
const http: httpm.HttpClient = new httpm.HttpClient('http-client-tests')
|
||||||
|
const res: httpm.HttpClientResponse = await http.get(
|
||||||
|
'https://postman-echo.com/get'
|
||||||
|
)
|
||||||
|
expect(res.message.statusCode).toBe(200)
|
||||||
|
const body: string = await res.readBody()
|
||||||
|
const obj = JSON.parse(body)
|
||||||
|
expect(obj.headers['user-agent']).toBe('http-client-tests')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses default user-agent with orchestration ID when no custom user-agent provided', async () => {
|
||||||
|
const orchId = 'test-default-id-12345'
|
||||||
|
process.env['ACTIONS_ORCHESTRATION_ID'] = orchId
|
||||||
|
|
||||||
|
const http: httpm.HttpClient = new httpm.HttpClient()
|
||||||
|
const res: httpm.HttpClientResponse = await http.get(
|
||||||
|
'https://postman-echo.com/get'
|
||||||
|
)
|
||||||
|
expect(res.message.statusCode).toBe(200)
|
||||||
|
const body: string = await res.readBody()
|
||||||
|
const obj = JSON.parse(body)
|
||||||
|
expect(obj.headers['user-agent']).toBe(
|
||||||
|
`actions/http-client actions_orchestration_id/${orchId}`
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export class HttpClient {
|
|||||||
handlers?: ifm.RequestHandler[],
|
handlers?: ifm.RequestHandler[],
|
||||||
requestOptions?: ifm.RequestOptions
|
requestOptions?: ifm.RequestOptions
|
||||||
) {
|
) {
|
||||||
this.userAgent = userAgent
|
this.userAgent = this._getUserAgentWithOrchestrationId(userAgent)
|
||||||
this.handlers = handlers || []
|
this.handlers = handlers || []
|
||||||
this.requestOptions = requestOptions
|
this.requestOptions = requestOptions
|
||||||
if (requestOptions) {
|
if (requestOptions) {
|
||||||
@@ -816,6 +816,18 @@ export class HttpClient {
|
|||||||
return proxyAgent
|
return proxyAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getUserAgentWithOrchestrationId(userAgent?: string): string {
|
||||||
|
const baseUserAgent = userAgent || 'actions/http-client'
|
||||||
|
const orchId = process.env['ACTIONS_ORCHESTRATION_ID']
|
||||||
|
if (orchId) {
|
||||||
|
// Sanitize the orchestration ID to ensure it contains only valid characters
|
||||||
|
// Valid characters: 0-9, a-z, _, -, .
|
||||||
|
const sanitizedId = orchId.replace(/[^a-z0-9_.-]/gi, '_')
|
||||||
|
return `${baseUserAgent} actions_orchestration_id/${sanitizedId}`
|
||||||
|
}
|
||||||
|
return baseUserAgent
|
||||||
|
}
|
||||||
|
|
||||||
private async _performExponentialBackoff(retryNumber: number): Promise<void> {
|
private async _performExponentialBackoff(retryNumber: number): Promise<void> {
|
||||||
retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber)
|
retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber)
|
||||||
const ms: number = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber)
|
const ms: number = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber)
|
||||||
|
|||||||
Reference in New Issue
Block a user