@@ -51,10 +51,13 @@ fn virtualize_child_env_replaces_supported_credentials() {
5151 let broker = CredentialBroker :: new ( /*enabled*/ true ) ;
5252 let github_token = "github_pat_11AA0bbCC_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGH" ;
5353 let openai_api_key = "sk-proj-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" ;
54+ let authorization = format ! ( "Bearer {github_token}" ) ;
5455 let mut env = env_map ( [
5556 ( "GH_TOKEN" , github_token) ,
57+ ( "HOMEBREW_GITHUB_API_TOKEN" , github_token) ,
58+ ( "AUTH_HEADER" , authorization. as_str ( ) ) ,
5659 ( "OPENAI_API_KEY" , openai_api_key) ,
57- ( "GH_ENTERPRISE_TOKEN" , "ghp-enterprise-real" ) ,
60+ ( "GH_ENTERPRISE_TOKEN" , github_token ) ,
5861 ] ) ;
5962
6063 broker. virtualize_child_env ( & mut env) ;
@@ -63,30 +66,74 @@ fn virtualize_child_env_replaces_supported_credentials() {
6366 let openai_dummy = env. get ( "OPENAI_API_KEY" ) . expect ( "dummy OpenAI API key" ) ;
6467 assert_credential_shape ( github_token, github_dummy, "github_pat_" ) ;
6568 assert_credential_shape ( openai_api_key, openai_dummy, "sk-proj-" ) ;
69+ assert_eq ! ( env. get( "HOMEBREW_GITHUB_API_TOKEN" ) , Some ( github_dummy) ) ;
70+ assert_eq ! ( env. get( "GH_ENTERPRISE_TOKEN" ) , Some ( github_dummy) ) ;
71+ assert_eq ! (
72+ env. get( "AUTH_HEADER" ) ,
73+ Some ( & format!( "Bearer {github_dummy}" ) )
74+ ) ;
75+ let mut persisted_credentials = format ! ( "{github_token}\n {openai_api_key}" ) ;
76+ assert ! ( broker. virtualize_text( & mut persisted_credentials, & env) ) ;
77+ assert_eq ! (
78+ persisted_credentials,
79+ format!( "{github_dummy}\n {openai_dummy}" )
80+ ) ;
81+ let mut filtered_env = env. clone ( ) ;
82+ filtered_env. remove ( "OPENAI_API_KEY" ) ;
83+ let mut excluded_credentials = format ! ( "{github_token}\n {openai_api_key}" ) ;
84+ assert ! ( !broker. virtualize_text( & mut excluded_credentials, & filtered_env) ) ;
85+ assert_eq ! ( excluded_credentials, format!( "{github_dummy}\n " ) ) ;
86+ let mut excluded_dummies = format ! ( "{github_dummy}\n {openai_dummy}" ) ;
87+ assert ! ( !broker. virtualize_text( & mut excluded_dummies, & filtered_env) ) ;
88+ assert_eq ! ( excluded_dummies, format!( "{github_dummy}\n " ) ) ;
6689 let mut command = vec ! [
6790 format!( "Authorization: Bearer {github_dummy}" ) ,
6891 format!( "Authorization: Bearer {openai_dummy}" ) ,
6992 ] ;
93+ let github_dummy = github_dummy. clone ( ) ;
7094 let openai_dummy = openai_dummy. clone ( ) ;
7195 env. insert ( "OPENAI_API_KEY" . to_string ( ) , "sk-user-override" . to_string ( ) ) ;
96+ env. insert (
97+ "GIT_CONFIG_VALUE_0" . to_string ( ) ,
98+ format ! ( "Authorization: Bearer {github_dummy}" ) ,
99+ ) ;
72100 assert_eq ! (
73101 brokered_credential_dummy_env_keys( & env) ,
74102 vec![ "GH_TOKEN" . to_string( ) ]
75103 ) ;
76104
77105 broker. restore_child_env ( & mut env, & mut command) ;
78106 assert_eq ! ( env. get( "GH_TOKEN" ) . map( String :: as_str) , Some ( github_token) ) ;
107+ assert_eq ! (
108+ env. get( "HOMEBREW_GITHUB_API_TOKEN" ) . map( String :: as_str) ,
109+ Some ( github_token)
110+ ) ;
111+ assert_eq ! (
112+ env. get( "GH_ENTERPRISE_TOKEN" ) . map( String :: as_str) ,
113+ Some ( github_token)
114+ ) ;
115+ assert_eq ! ( env. get( "AUTH_HEADER" ) , Some ( & authorization) ) ;
79116 assert_eq ! (
80117 env. get( "OPENAI_API_KEY" ) . map( String :: as_str) ,
81118 Some ( "sk-user-override" )
82119 ) ;
120+ assert_eq ! (
121+ env. get( "GIT_CONFIG_VALUE_0" ) ,
122+ Some ( & format!( "Authorization: Bearer {github_dummy}" ) )
123+ ) ;
83124 assert_eq ! (
84125 command,
85126 vec![
86- format!( "Authorization: Bearer {github_token }" ) ,
127+ format!( "Authorization: Bearer {github_dummy }" ) ,
87128 format!( "Authorization: Bearer {openai_dummy}" ) ,
88129 ]
89130 ) ;
131+
132+ env. insert ( "GH_TOKEN" . to_string ( ) , openai_dummy. clone ( ) ) ;
133+ env. insert ( "OPENAI_API_KEY" . to_string ( ) , github_dummy. clone ( ) ) ;
134+ broker. restore_child_env ( & mut env, & mut [ ] ) ;
135+ assert_eq ! ( env. get( "GH_TOKEN" ) , Some ( & openai_dummy) ) ;
136+ assert_eq ! ( env. get( "OPENAI_API_KEY" ) , Some ( & github_dummy) ) ;
90137}
91138
92139#[ cfg( windows) ]
@@ -130,6 +177,119 @@ fn virtualize_child_env_preserves_live_dummy_mappings() {
130177
131178 assert_eq ! ( authorization( & first_headers) , Some ( "Bearer ghp-real-one" ) ) ;
132179 assert_eq ! ( authorization( & second_headers) , Some ( "Bearer ghp-real-two" ) ) ;
180+
181+ let mut alias_only = env_map ( [ ( "HOMEBREW_GITHUB_API_TOKEN" , "ghp-real-one" ) ] ) ;
182+ broker. virtualize_child_env ( & mut alias_only) ;
183+ assert_eq ! (
184+ alias_only. get( "HOMEBREW_GITHUB_API_TOKEN" ) ,
185+ Some ( first_dummy)
186+ ) ;
187+ broker. restore_child_env ( & mut alias_only, & mut [ ] ) ;
188+ assert_eq ! ( alias_only[ "HOMEBREW_GITHUB_API_TOKEN" ] , "ghp-real-one" ) ;
189+
190+ let mut overridden = env_map ( [
191+ ( "GH_TOKEN" , "ghp-real-two" ) ,
192+ ( "HOMEBREW_GITHUB_API_TOKEN" , "ghp-real-one" ) ,
193+ ] ) ;
194+ broker. virtualize_child_env ( & mut overridden) ;
195+ assert_eq ! ( overridden. get( "GH_TOKEN" ) , Some ( second_dummy) ) ;
196+ assert_eq ! (
197+ overridden. get( "HOMEBREW_GITHUB_API_TOKEN" ) ,
198+ Some ( first_dummy)
199+ ) ;
200+
201+ let mut cloud_alias = env_map ( [
202+ ( "GH_TOKEN" , "ghp-real-one" ) ,
203+ ( "GITHUB_TOKEN" , "ghp-real-one" ) ,
204+ ] ) ;
205+ broker. virtualize_child_env ( & mut cloud_alias) ;
206+ cloud_alias. insert ( "GITHUB_TOKEN" . to_string ( ) , first_dummy. clone ( ) ) ;
207+ broker. restore_child_env ( & mut cloud_alias, & mut [ ] ) ;
208+ assert_eq ! ( cloud_alias[ "GITHUB_TOKEN" ] , "ghp-real-one" ) ;
209+
210+ let mut distinct_credentials = env_map ( [
211+ ( "GH_TOKEN" , "ghp-primary-secret" ) ,
212+ ( "GITHUB_TOKEN" , "ghp-secondary-secret" ) ,
213+ ] ) ;
214+ broker. virtualize_child_env ( & mut distinct_credentials) ;
215+ let secondary_dummy = distinct_credentials[ "GITHUB_TOKEN" ] . clone ( ) ;
216+ distinct_credentials. remove ( "GITHUB_TOKEN" ) ;
217+ distinct_credentials. insert ( "GH_TOKEN" . to_string ( ) , secondary_dummy. clone ( ) ) ;
218+ broker. virtualize_child_env ( & mut distinct_credentials) ;
219+ broker. restore_child_env ( & mut distinct_credentials, & mut [ ] ) ;
220+ assert_eq ! ( distinct_credentials[ "GH_TOKEN" ] , secondary_dummy) ;
221+ }
222+
223+ #[ test]
224+ fn virtualize_child_env_replaces_aliases_of_filtered_parent_credentials ( ) {
225+ let broker = CredentialBroker :: new ( /*enabled*/ true ) ;
226+ let github_token = "ghp_abcdefghijklmnopqrstuvwxyz1234567890" ;
227+ let authorization_header = format ! ( "Bearer {github_token}" ) ;
228+ let parent_env = env_map ( [
229+ ( "GH_TOKEN" , github_token) ,
230+ ( "HOMEBREW_GITHUB_API_TOKEN" , github_token) ,
231+ ] ) ;
232+ let mut child_env = env_map ( [
233+ ( "HOMEBREW_GITHUB_API_TOKEN" , github_token) ,
234+ ( "AUTH_HEADER" , authorization_header. as_str ( ) ) ,
235+ ] ) ;
236+
237+ broker. discover_parent_credentials ( & parent_env, & child_env) ;
238+ broker. virtualize_child_env ( & mut child_env) ;
239+
240+ let dummy = child_env[ "HOMEBREW_GITHUB_API_TOKEN" ] . clone ( ) ;
241+ assert_ne ! ( dummy, github_token) ;
242+ assert_eq ! ( child_env[ "AUTH_HEADER" ] , format!( "Bearer {dummy}" ) ) ;
243+ assert ! ( !child_env. contains_key( "GH_TOKEN" ) ) ;
244+
245+ let mut headers = headers_with_bearer ( & dummy) ;
246+ broker. inject_request_headers ( "api.github.com" , & mut headers) ;
247+ assert_eq ! ( authorization( & headers) , Some ( authorization_header. as_str( ) ) ) ;
248+
249+ broker. restore_child_env ( & mut child_env, & mut [ ] ) ;
250+ assert_eq ! ( child_env[ "HOMEBREW_GITHUB_API_TOKEN" ] , github_token) ;
251+ assert_eq ! ( child_env[ "AUTH_HEADER" ] , authorization_header) ;
252+ assert ! ( !child_env. contains_key( "GH_TOKEN" ) ) ;
253+ }
254+
255+ #[ test]
256+ fn virtualize_child_env_binds_filtered_enterprise_credentials_to_child_host ( ) {
257+ let github_token = "ghp_abcdefghijklmnopqrstuvwxyz1234567890" ;
258+ let authorization_header = format ! ( "Bearer {github_token}" ) ;
259+
260+ for ( parent_host, include_cloud_token) in [
261+ ( None , false ) ,
262+ ( Some ( "github.previous.example" ) , false ) ,
263+ ( None , true ) ,
264+ ] {
265+ let broker = CredentialBroker :: new ( /*enabled*/ true ) ;
266+ let mut parent_env = env_map ( [ ( "GH_ENTERPRISE_TOKEN" , github_token) ] ) ;
267+ if let Some ( parent_host) = parent_host {
268+ parent_env. insert ( "GH_HOST" . to_string ( ) , parent_host. to_string ( ) ) ;
269+ }
270+ if include_cloud_token {
271+ parent_env. insert ( "GH_TOKEN" . to_string ( ) , github_token. to_string ( ) ) ;
272+ }
273+ let mut child_env = env_map ( [
274+ ( "GH_HOST" , "github.current.example" ) ,
275+ ( "AUTH_HEADER" , authorization_header. as_str ( ) ) ,
276+ ] ) ;
277+
278+ broker. discover_parent_credentials ( & parent_env, & child_env) ;
279+ broker. virtualize_child_env ( & mut child_env) ;
280+
281+ assert_ne ! ( child_env[ "AUTH_HEADER" ] , authorization_header) ;
282+ let mut headers = headers_with_authorization ( & child_env[ "AUTH_HEADER" ] ) ;
283+ broker. inject_request_headers ( "github.current.example" , & mut headers) ;
284+ assert_eq ! ( authorization( & headers) , Some ( authorization_header. as_str( ) ) ) ;
285+
286+ let mut previous_headers = headers_with_authorization ( & child_env[ "AUTH_HEADER" ] ) ;
287+ broker. inject_request_headers ( "github.previous.example" , & mut previous_headers) ;
288+ assert_eq ! (
289+ authorization( & previous_headers) ,
290+ Some ( child_env[ "AUTH_HEADER" ] . as_str( ) )
291+ ) ;
292+ }
133293}
134294
135295#[ test]
@@ -192,6 +352,12 @@ fn virtualize_child_env_preserves_unbound_enterprise_token() {
192352 assert_eq ! ( env[ "GH_ENTERPRISE_TOKEN" ] , "ghp-enterprise-real" ) ;
193353 assert_eq ! ( headers, headers_with_bearer( inert_token) ) ;
194354 assert ! ( !broker. host_requires_mitm( "attacker.example" ) ) ;
355+
356+ env. insert ( "GH_HOST" . to_string ( ) , "github.example.com" . to_string ( ) ) ;
357+ broker. virtualize_child_env ( & mut env) ;
358+ let mut headers = headers_with_bearer ( & env[ "GH_ENTERPRISE_TOKEN" ] ) ;
359+ broker. inject_request_headers ( "github.example.com" , & mut headers) ;
360+ assert_eq ! ( authorization( & headers) , Some ( "Bearer ghp-enterprise-real" ) ) ;
195361}
196362
197363#[ test]
@@ -294,6 +460,7 @@ fn openai_credentials_bind_only_to_default_and_configured_trusted_hosts() {
294460 ] ) ;
295461 broker. virtualize_child_env ( & mut env) ;
296462 assert ! ( brokered_credential_env_keys( & env) . any( |key| key == "OPENAI_BASE_URL" ) ) ;
463+ assert ! ( brokered_credential_binding_env_keys( & env) . any( |key| key == "OPENAI_BASE_URL" ) ) ;
297464 let dummy = & env[ "OPENAI_API_KEY" ] ;
298465
299466 for ( host, expected_credential) in [
@@ -330,6 +497,7 @@ fn github_cloud_credentials_match_ghe_com_host_hint() {
330497 let broker = CredentialBroker :: new ( /*enabled*/ true ) ;
331498 let mut env = env_map ( [ ( "GH_HOST" , "astemu.ghe.com" ) , ( "GH_TOKEN" , "ghp-real" ) ] ) ;
332499 broker. virtualize_child_env ( & mut env) ;
500+ assert ! ( !brokered_credential_binding_env_keys( & env) . any( |key| key == "GH_HOST" ) ) ;
333501 let github_token = env. get ( "GH_TOKEN" ) . expect ( "dummy GitHub token" ) ;
334502 let mut headers = headers_with_bearer ( github_token) ;
335503
@@ -362,18 +530,77 @@ fn github_enterprise_credentials_bind_to_gh_host() {
362530 let broker = CredentialBroker :: new ( /*enabled*/ true ) ;
363531 let mut env = env_map ( [
364532 ( "GH_HOST" , "github.example.com" ) ,
533+ ( "GH_TOKEN" , "ghp-enterprise-real" ) ,
365534 ( "GH_ENTERPRISE_TOKEN" , "ghp-enterprise-real" ) ,
535+ ( "AUTH_HEADER" , "Bearer ghp-enterprise-real" ) ,
366536 ] ) ;
367537 broker. virtualize_child_env ( & mut env) ;
538+ let github_dummy = env[ "GH_TOKEN" ] . clone ( ) ;
368539 assert ! ( brokered_credential_env_keys( & env) . any( |key| key == "GH_HOST" ) ) ;
540+ assert ! ( brokered_credential_binding_env_keys( & env) . any( |key| key == "GH_HOST" ) ) ;
369541 let github_token = env
370542 . get ( "GH_ENTERPRISE_TOKEN" )
371543 . expect ( "dummy GitHub enterprise token" ) ;
544+ assert_ne ! ( github_token, & github_dummy) ;
372545 let mut headers = headers_with_bearer ( github_token) ;
373546
374547 broker. inject_request_headers ( "github.example.com" , & mut headers) ;
375548
376549 assert_eq ! ( authorization( & headers) , Some ( "Bearer ghp-enterprise-real" ) ) ;
550+ assert_eq ! ( env[ "AUTH_HEADER" ] , format!( "Bearer {github_token}" ) ) ;
551+ let mut alias_headers = headers_with_authorization ( & env[ "AUTH_HEADER" ] ) ;
552+ broker. inject_request_headers ( "github.example.com" , & mut alias_headers) ;
553+ assert_eq ! (
554+ authorization( & alias_headers) ,
555+ Some ( "Bearer ghp-enterprise-real" )
556+ ) ;
557+ let mut persisted_alias = "Bearer ghp-enterprise-real" . to_string ( ) ;
558+ assert ! ( broker. virtualize_text( & mut persisted_alias, & env) ) ;
559+ assert_eq ! ( persisted_alias, format!( "Bearer {github_token}" ) ) ;
560+ assert_eq ! (
561+ brokered_credential_dummy_env_keys( & env) . first( ) ,
562+ Some ( & "GH_ENTERPRISE_TOKEN" . to_string( ) )
563+ ) ;
564+ let mut cloud_headers = headers_with_bearer ( & github_dummy) ;
565+ broker. inject_request_headers ( "github.example.com" , & mut cloud_headers) ;
566+ assert_eq ! ( cloud_headers, headers_with_bearer( & github_dummy) ) ;
567+ let mut enterprise_headers = headers_with_bearer ( github_token) ;
568+ broker. inject_request_headers ( "api.github.com" , & mut enterprise_headers) ;
569+ assert_eq ! ( enterprise_headers, headers_with_bearer( github_token) ) ;
570+ let mut cloud_only = env_map ( [
571+ ( "GH_HOST" , "github.example.com" ) ,
572+ ( "GH_TOKEN" , "ghp-enterprise-real" ) ,
573+ ( "AUTH_HEADER" , "Bearer ghp-enterprise-real" ) ,
574+ ] ) ;
575+ broker. virtualize_child_env ( & mut cloud_only) ;
576+ assert_eq ! ( cloud_only[ "AUTH_HEADER" ] , format!( "Bearer {github_dummy}" ) ) ;
377577 assert ! ( broker. host_requires_mitm( "github.example.com" ) ) ;
378- assert ! ( !broker. host_requires_mitm( "api.github.com" ) ) ;
578+ assert ! ( broker. host_requires_mitm( "api.github.com" ) ) ;
579+
580+ env. insert ( "GH_HOST" . to_string ( ) , "attacker.example" . to_string ( ) ) ;
581+ env. insert ( "GH_ENTERPRISE_TOKEN" . to_string ( ) , github_dummy. clone ( ) ) ;
582+ broker. virtualize_child_env ( & mut env) ;
583+ let mut attacker_headers = headers_with_bearer ( & github_dummy) ;
584+ broker. inject_request_headers ( "attacker.example" , & mut attacker_headers) ;
585+ assert_eq ! ( attacker_headers, headers_with_bearer( & github_dummy) ) ;
586+ assert ! ( !broker. host_requires_mitm( "attacker.example" ) ) ;
587+
588+ let mut alternate_enterprise_key = env_map ( [
589+ ( "GH_HOST" , "github.alternate.example" ) ,
590+ ( "GH_TOKEN" , "ghp-alternate-real" ) ,
591+ ( "GITHUB_ENTERPRISE_TOKEN" , "ghp-alternate-real" ) ,
592+ ( "AUTH_HEADER" , "Bearer ghp-alternate-real" ) ,
593+ ] ) ;
594+ broker. virtualize_child_env ( & mut alternate_enterprise_key) ;
595+ assert_eq ! (
596+ alternate_enterprise_key[ "AUTH_HEADER" ] ,
597+ format!(
598+ "Bearer {}" ,
599+ alternate_enterprise_key[ "GITHUB_ENTERPRISE_TOKEN" ]
600+ )
601+ ) ;
602+ assert_eq ! (
603+ brokered_credential_dummy_env_keys( & alternate_enterprise_key) . first( ) ,
604+ Some ( & "GITHUB_ENTERPRISE_TOKEN" . to_string( ) )
605+ ) ;
379606}
0 commit comments