@@ -438,7 +438,7 @@ describe("secret-guard file URL normalization", () => {
438438 ) ;
439439 }
440440
441- const schemeBraceURLs = [
441+ const synthesizedSchemeURLs = [
442442 "{file,https}:///tmp/%2Eenv" ,
443443 "{https,file}:///tmp/%2Eenv" ,
444444 "file{,s}:///tmp/%2Eenv" ,
@@ -449,9 +449,13 @@ describe("secret-guard file URL normalization", () => {
449449 "{https://127.0.0.1:1/README.md,file:///tmp/%2Eenv}" ,
450450 "f{i,oo}{le,tp}:///tmp/%2Eenv" ,
451451 "F{ILE,OO}:///tmp/%2Eenv" ,
452+ "f[i-i]le:///tmp/%2Eenv" ,
453+ "f[a-z]le:///tmp/%2Eenv" ,
454+ "F[I-I]LE:///tmp/%2Eenv" ,
455+ "f[i-i]l{e,x}:///tmp/%2Eenv" ,
452456 ] ;
453457
454- for ( const url of schemeBraceURLs ) {
458+ for ( const url of synthesizedSchemeURLs ) {
455459 test . skipIf ( Bun . which ( "curl" ) === null ) (
456460 `flags curl scheme synthesis that reads a real .env: ${ url } ` ,
457461 async ( ) => {
@@ -483,31 +487,84 @@ describe("secret-guard file URL normalization", () => {
483487 ) ;
484488 }
485489
486- test ( "keeps remote-only scheme braces allowed" , ( ) => {
490+ test ( "keeps remote-only scheme globs allowed" , ( ) => {
487491 const overflow = `{${ Array . from ( { length : 80 } , ( _ , index ) =>
488492 index % 2 === 0 ? "https" : "http" ,
489493 ) . join ( "," ) } }://example.com/{one,two}`;
494+ const overlength = `{${ Array . from ( { length : 800 } , ( _ , index ) =>
495+ index % 2 === 0 ? "https" : "http" ,
496+ ) . join ( "," ) } }://example.com/{one,two}`;
490497 for ( const url of [
491498 "{https,http}://example.com/{one,two}" ,
492499 "{http,https}://example.com/{one,two}" ,
493500 "h{ttp,ttps}://example.com/{one,two}" ,
501+ "{{https,http},{http,https}}://example.com/{one,two}" ,
502+ "h{ttp,ttps}{,s}://example.com/{one,two}" ,
503+ "h[t-t]tp://example.com/[a-z]" ,
504+ "https://example.com/[a-z]?q=[0-9]" ,
494505 overflow ,
506+ overlength ,
495507 `https://example.com/${ "x" . repeat ( 4_096 ) } /{one,two}` ,
496508 ] ) {
497509 expect ( commandReferencesSensitivePath ( `curl '${ url } '` ) ) . toBeUndefined ( ) ;
498510 }
499511 } ) ;
500512
501- test ( "fails closed for ambiguous and overflowing file-scheme braces" , ( ) => {
513+ test ( "classifies 1000 remote-only bracket URLs within a bounded time" , ( ) => {
514+ const url = `f[t-t]p://example.com/${ "[a-z]" . repeat ( 1_000 ) } ` ;
515+ const started = performance . now ( ) ;
516+ for ( let index = 0 ; index < 1_000 ; index ++ ) {
517+ expect ( commandReferencesSensitivePath ( `curl '${ url } '` ) ) . toBeUndefined ( ) ;
518+ }
519+ expect ( performance . now ( ) - started ) . toBeLessThan ( 1_000 ) ;
520+ } ) ;
521+
522+ test ( "fails closed for file-capable scheme braces in any position" , ( ) => {
523+ const remote : string [ ] = Array . from ( { length : 800 } , ( _ , index ) =>
524+ index % 2 === 0 ? "https" : "http" ,
525+ ) ;
526+ const withFileAt = ( index : number ) => {
527+ const schemes = [ ...remote ] ;
528+ schemes [ index ] = "file" ;
529+ return `{${ schemes . join ( "," ) } }:///tmp/%2Eenv` ;
530+ } ;
531+ for ( const url of [
532+ withFileAt ( 0 ) ,
533+ withFileAt ( 400 ) ,
534+ withFileAt ( 799 ) ,
535+ "{{https,http},{ftp,file}}:///tmp/%2Eenv" ,
536+ "{f,h}{ile,ttps}:///tmp/%2Eenv" ,
537+ ] ) {
538+ expect ( commandReferencesSensitivePath ( `curl '${ url } '` ) ) . toBeDefined ( ) ;
539+ }
540+ } ) ;
541+
542+ test ( "classifies a 100x remote-only alternative list within a bounded time" , ( ) => {
543+ const url = `{${ Array . from ( { length : 80_000 } , ( _ , index ) =>
544+ index % 2 === 0 ? "https" : "http" ,
545+ ) . join ( "," ) } }://example.com/{one,two}`;
546+ const started = performance . now ( ) ;
547+ expect ( commandReferencesSensitivePath ( `curl '${ url } '` ) ) . toBeUndefined ( ) ;
548+ expect ( performance . now ( ) - started ) . toBeLessThan ( 1_000 ) ;
549+ } ) ;
550+
551+ test ( "fails closed for ambiguous and overflowing file-scheme globs" , ( ) => {
502552 const overflow = `f{${ Array . from ( { length : 80 } , ( _ , index ) =>
503553 index === 79 ? "ile" : `x${ index } ` ,
504554 ) . join ( "," ) } }:///tmp/%2Eenv`;
505555 const overlength = `f{ile,${ "x" . repeat ( 4_096 ) } }:///tmp/%2Eenv` ;
556+ const malformedOverlength = `{${ Array . from ( { length : 800 } , ( _ , index ) =>
557+ index === 799 ? "f{ile" : "https" ,
558+ ) . join ( "," ) } :///tmp/%2Eenv`;
506559 for ( const url of [
507560 "f{ile:,https:///tmp/%2Eenv" ,
508561 "f{i,{oo,ILE}}:///tmp/%2Eenv" ,
562+ "f[i]le:///tmp/%2Eenv" ,
563+ "f[i-i le:///tmp/%2Eenv" ,
564+ "f[i,i]le:///tmp/%2Eenv" ,
509565 overflow ,
510566 overlength ,
567+ malformedOverlength ,
511568 ] ) {
512569 expect ( commandReferencesSensitivePath ( `curl '${ url } '` ) ) . toBeDefined ( ) ;
513570 }
0 commit comments