@@ -232,7 +232,7 @@ describe('OCI request client', () => {
232232 maxResponseBytes : 65_536 ,
233233 } ) . catch ( ( error : unknown ) => error )
234234 expect ( failure ) . toBeInstanceOf ( OciRequestError )
235- expect ( ( failure as Error ) . message ) . toContain ( '[REDACTED] ')
235+ expect ( ( failure as Error ) . message ) . toBe ( 'OCI request failed with status 401 ')
236236 expect ( ( failure as Error ) . message ) . not . toContain ( 'provider-echo' )
237237 expect ( ( failure as Error ) . message ) . not . toContain ( '(request-target)' )
238238 expect ( ( failure as Error ) . message ) . not . toContain ( 'tenant/user/fingerprint' )
@@ -298,6 +298,8 @@ describe('OCI request client', () => {
298298 it . each ( [
299299 encodeURIComponent ( '-----BEGIN PRIVATE KEY-----\ntruncated' ) ,
300300 encodeURIComponent ( `${ destination . origin } /n/truncated` ) ,
301+ '----%2DBEGIN PRIVATE KEY-----' ,
302+ 'https:%2F%2Fobjectstorage.us-ashburn-1.oraclecloud.com/n/' ,
301303 ] ) ( 'fails closed for encoded key or URL prefixes' , async ( message ) => {
302304 secureFetchMock . mockResolvedValueOnce (
303305 secureResponse ( {
@@ -324,6 +326,8 @@ describe('OCI request client', () => {
324326 'secret-value' ,
325327 'password-value' ,
326328 '(request-target) host x-date' ,
329+ 'private-key-value' ,
330+ 'api-key-value' ,
327331 ]
328332 secureFetchMock . mockResolvedValueOnce (
329333 secureResponse ( {
@@ -337,6 +341,8 @@ describe('OCI request client', () => {
337341 secret : echoedSecrets [ 2 ] ,
338342 'pass%70hrase' : echoedSecrets [ 3 ] ,
339343 signing_string : echoedSecrets [ 4 ] ,
344+ 'private key' : echoedSecrets [ 5 ] ,
345+ 'api key' : echoedSecrets [ 6 ] ,
340346 } ) ,
341347 } ) ,
342348 } )
@@ -352,6 +358,50 @@ describe('OCI request client', () => {
352358 for ( const secret of echoedSecrets ) expect ( ( failure as Error ) . message ) . not . toContain ( secret )
353359 } )
354360
361+ it ( 'fails closed when structured JSON follows a plain-text prefix' , async ( ) => {
362+ const message = `provider failed: ${ JSON . stringify ( { authorization : 'provider-echo' } ) } `
363+ secureFetchMock . mockResolvedValueOnce (
364+ secureResponse ( {
365+ ok : false ,
366+ status : 401 ,
367+ body : JSON . stringify ( { code : 'NotAuthenticated' , message } ) ,
368+ } )
369+ )
370+ const failure = await sendOciRequest ( {
371+ destination,
372+ credentials,
373+ method : 'GET' ,
374+ encodedPath : '/n/' ,
375+ timeout : 10_000 ,
376+ maxResponseBytes : 65_536 ,
377+ } ) . catch ( ( error : unknown ) => error )
378+ expect ( ( failure as Error ) . message ) . toBe ( 'OCI request failed with status 401' )
379+ } )
380+
381+ it . each ( [
382+ `provider failed: ${ JSON . stringify ( JSON . stringify ( { authorization : 'provider-echo' } ) ) } ` ,
383+ 'provider failed: \\"authorization\\":\\"provider-echo\\"' ,
384+ 'signed headers: (request-target) host x-date' ,
385+ 'signed headers: host x-content-sha256' ,
386+ ] ) ( 'fails closed for escaped structured or signing diagnostics' , async ( message ) => {
387+ secureFetchMock . mockResolvedValueOnce (
388+ secureResponse ( {
389+ ok : false ,
390+ status : 401 ,
391+ body : JSON . stringify ( { code : 'NotAuthenticated' , message } ) ,
392+ } )
393+ )
394+ const failure = await sendOciRequest ( {
395+ destination,
396+ credentials,
397+ method : 'GET' ,
398+ encodedPath : '/n/' ,
399+ timeout : 10_000 ,
400+ maxResponseBytes : 65_536 ,
401+ } ) . catch ( ( error : unknown ) => error )
402+ expect ( ( failure as Error ) . message ) . toBe ( 'OCI request failed with status 401' )
403+ } )
404+
355405 it . each ( [
356406 '{"authorization":"Signature version=\\"1\\",signature=\\"echoed\\"' ,
357407 JSON . stringify ( { level1 : { level2 : { level3 : { authorization : 'echoed' } } } } ) ,
0 commit comments