Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions packages/cli/src/rest/__tests__/request-interceptor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'

// api.ts builds its axios instance and resource classes at import time via
// getDefaults(); stub the config service so importing it needs no credentials.
vi.mock('../../services/config.js', () => ({
default: {
getApiKey: () => 'test-key',
getAccountId: () => 'test-account',
getApiUrl: () => 'https://api.checklyhq.com',
hasValidCredentials: () => true,
},
}))

vi.mock('../../helpers/cli-mode.js', () => ({
detectCliMode: vi.fn(() => 'interactive'),
detectOperator: vi.fn(() => 'manual'),
}))

import { requestInterceptor } from '../api.js'
import { detectCliMode } from '../../helpers/cli-mode.js'

describe('requestInterceptor x-checkly-source', () => {
const sourceHeader = () => {
const config = { headers: {} } as any
return requestInterceptor(config).headers['x-checkly-source']
}

beforeEach(() => {
vi.clearAllMocks()
})

it('reports AGENT when the CLI is driven by an agent', () => {
vi.mocked(detectCliMode).mockReturnValue('agent')
expect(sourceHeader()).toBe('AGENT')
})

it('reports CLI for interactive and CI runs', () => {
vi.mocked(detectCliMode).mockReturnValue('interactive')
expect(sourceHeader()).toBe('CLI')

vi.mocked(detectCliMode).mockReturnValue('ci')
expect(sourceHeader()).toBe('CLI')
})
})
7 changes: 5 additions & 2 deletions packages/cli/src/rest/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import AlertNotifications from './alert-notifications.js'
import Rca from './rca.js'
import Cancel from './cancel.js'
import { handleErrorResponse, UnauthorizedError } from './errors.js'
import { detectOperator } from '../helpers/cli-mode.js'
import { detectCliMode, detectOperator } from '../helpers/cli-mode.js'

export function getDefaults () {
const apiKey = config.getApiKey()
Expand Down Expand Up @@ -82,7 +82,10 @@ export function requestInterceptor (config: InternalAxiosRequestConfig) {
config.headers['x-checkly-account'] = accountId
}

config.headers['x-checkly-source'] = 'CLI'
// Declare who is driving the CLI. An agent run reports `AGENT` so the backend
// can tell agent-created import plans apart from human ones (same API key) —
// it keys the abandoned-reservation GC off this. Everything else is `CLI`.
config.headers['x-checkly-source'] = detectCliMode() === 'agent' ? 'AGENT' : 'CLI'
config.headers['x-checkly-ci-name'] = CIname
config.headers['x-checkly-operator'] = detectOperator()

Expand Down
Loading