@@ -18,21 +18,17 @@ import {
1818import { CompoundEntityRef , Entity , stringifyEntityRef } from '@backstage/catalog-model' ;
1919import axios , { AxiosInstance , isAxiosError } from 'axios' ;
2020
21- import { type AuthConfig } from '../auth' ;
22- import { AuthManager } from '../auth/auth-manager' ;
23- import { securityAuditor , SecurityEventType } from '../auth/security-auditor' ;
24- import { CacheManager } from '../cache/cache-manager' ;
25- import { logger } from '../utils' ;
26- import { isString } from '../utils/guards' ;
27- import { JsonApiDocument , JsonApiFormatter } from '../utils/jsonapi-formatter' ;
28- import { PaginationHelper , PaginationParams } from '../utils/pagination-helper' ;
21+ import { AuthConfig , AuthManager , securityAuditor } from '../auth' ;
22+ import { CacheManager } from '../cache' ;
23+ import { IBackstageCatalogApi , JsonApiDocument , PaginationParams , SecurityEventType } from '../types' ;
24+ import { isNonEmptyString , isNumber , isString , JsonApiFormatter , logger , PaginationHelper } from '../utils' ;
2925
3026interface BackstageCatalogApiOptions {
3127 baseUrl : string ;
3228 auth : AuthConfig ;
3329}
3430
35- export class BackstageCatalogApi {
31+ export class BackstageCatalogApi implements IBackstageCatalogApi {
3632 private readonly client : AxiosInstance ;
3733 private readonly authManager : AuthManager ;
3834 private readonly cacheManager : CacheManager ;
@@ -60,16 +56,13 @@ export class BackstageCatalogApi {
6056
6157 // Add authorization header if provided
6258 const authHeader = await this . authManager . getAuthorizationHeader ( ) ;
63- if ( typeof authHeader === 'string' && authHeader . length > 0 ) {
59+ if ( isNonEmptyString ( authHeader ) ) {
6460 config . headers . Authorization = authHeader ;
6561 }
6662
6763 // Log security event with explicit fallbacks
68- const resource = typeof config . url === 'string' && config . url . length > 0 ? String ( config . url ) : 'unknown' ;
69- const action =
70- typeof config . method === 'string' && config . method . length > 0
71- ? String ( config . method ) . toUpperCase ( )
72- : 'UNKNOWN' ;
64+ const resource = isNonEmptyString ( config . url ) ? String ( config . url ) : 'unknown' ;
65+ const action = isNonEmptyString ( config . method ) ? String ( config . method ) . toUpperCase ( ) : 'UNKNOWN' ;
7366
7467 securityAuditor . logEvent ( {
7568 type : SecurityEventType . AUTH_SUCCESS ,
@@ -85,20 +78,11 @@ export class BackstageCatalogApi {
8578 let resource : string = 'unknown' ;
8679 let action = 'UNKNOWN' ;
8780 if ( isAxiosError ( error ) ) {
88- resource =
89- typeof error . config ?. url === 'string' && error . config ?. url ! . length > 0
90- ? String ( error . config ! . url )
91- : resource ;
92- action =
93- typeof error . config ?. method === 'string' && error . config ?. method ! . length > 0
94- ? String ( error . config ! . method ) . toUpperCase ( )
95- : action ;
81+ resource = isNonEmptyString ( error . config ?. url ) ? String ( error . config ! . url ) : resource ;
82+ action = isNonEmptyString ( error . config ?. method ) ? String ( error . config ! . method ) . toUpperCase ( ) : action ;
9683 } else {
97- resource = typeof config . url === 'string' && config . url . length > 0 ? String ( config . url ) : resource ;
98- action =
99- typeof config . method === 'string' && config . method . length > 0
100- ? String ( config . method ) . toUpperCase ( )
101- : action ;
84+ resource = isNonEmptyString ( config . url ) ? String ( config . url ) : resource ;
85+ action = isNonEmptyString ( config . method ) ? String ( config . method ) . toUpperCase ( ) : action ;
10286 }
10387
10488 securityAuditor . logEvent ( {
@@ -118,14 +102,10 @@ export class BackstageCatalogApi {
118102 ( error ) => {
119103 // Log security events for certain error types. Narrow to axios errors first
120104 if ( isAxiosError ( error ) ) {
121- const resource =
122- typeof error . config ?. url === 'string' && error . config ?. url ! . length > 0
123- ? String ( error . config ! . url )
124- : 'unknown' ;
125- const action =
126- typeof error . config ?. method === 'string' && error . config ?. method ! . length > 0
127- ? String ( error . config ! . method ) . toUpperCase ( )
128- : 'UNKNOWN' ;
105+ const resource = isNonEmptyString ( error . config ?. url ) ? String ( error . config ! . url ) : 'unknown' ;
106+ const action = isNonEmptyString ( error . config ?. method )
107+ ? String ( error . config ! . method ) . toUpperCase ( )
108+ : 'UNKNOWN' ;
129109
130110 if ( error . response ?. status === 401 ) {
131111 securityAuditor . logEvent ( {
@@ -148,19 +128,15 @@ export class BackstageCatalogApi {
148128 // Fallback for non-axios errors that may still have a response shape
149129 const maybe = error as unknown as { response ?: { status ?: number } } | undefined ;
150130 const maybeResponse = maybe && maybe . response ? maybe . response : undefined ;
151- if ( maybeResponse !== undefined && typeof maybeResponse . status === 'number' && maybeResponse . status === 401 ) {
131+ if ( isNumber ( maybeResponse ? .status ) && maybeResponse . status === 401 ) {
152132 securityAuditor . logEvent ( {
153133 type : SecurityEventType . UNAUTHORIZED_ACCESS ,
154134 resource : 'unknown' ,
155135 action : 'UNKNOWN' ,
156136 success : false ,
157137 errorMessage : 'Unauthorized access' ,
158138 } ) ;
159- } else if (
160- maybeResponse !== undefined &&
161- typeof maybeResponse . status === 'number' &&
162- maybeResponse . status === 429
163- ) {
139+ } else if ( isNumber ( maybeResponse ?. status ) && maybeResponse . status === 429 ) {
164140 securityAuditor . logEvent ( {
165141 type : SecurityEventType . RATE_LIMIT_EXCEEDED ,
166142 resource : 'unknown' ,
@@ -344,7 +320,6 @@ export class BackstageCatalogApi {
344320 */
345321 async getEntitiesJsonApi ( request ?: GetEntitiesRequest & PaginationParams ) : Promise < JsonApiDocument > {
346322 const entities = await this . getEntities ( request ) ;
347-
348323 // Convert to JSON:API format
349324 return JsonApiFormatter . entitiesToDocument ( entities . items ?? [ ] ) ;
350325 }
0 commit comments