@@ -13,6 +13,8 @@ use crate::{
13
13
use gix_features:: threading:: OwnShared ;
14
14
use gix_object:: bstr:: ByteSlice ;
15
15
use gix_path:: RelativePath ;
16
+ use std:: collections:: btree_map:: Entry ;
17
+ use std:: collections:: BTreeMap ;
16
18
use std:: ffi:: OsStr ;
17
19
use std:: { borrow:: Cow , path:: PathBuf } ;
18
20
@@ -157,7 +159,7 @@ impl ThreadSafeRepository {
157
159
) -> Result < Self , Error > {
158
160
let _span = gix_trace:: detail!( "open_from_paths()" ) ;
159
161
let Options {
160
- git_dir_trust,
162
+ ref mut git_dir_trust,
161
163
object_store_slots,
162
164
filter_config_section,
163
165
lossy_config,
@@ -174,15 +176,15 @@ impl ThreadSafeRepository {
174
176
ref cli_config_overrides,
175
177
ref mut current_dir,
176
178
} = options;
177
- let git_dir_trust = git_dir_trust. expect ( "trust must be determined by now" ) ;
179
+ let git_dir_trust = git_dir_trust. as_mut ( ) . expect ( "trust must be determined by now" ) ;
178
180
179
181
let mut common_dir = gix_discover:: path:: from_plain_file ( git_dir. join ( "commondir" ) . as_ref ( ) )
180
182
. transpose ( ) ?
181
183
. map ( |cd| git_dir. join ( cd) ) ;
182
184
let repo_config = config:: cache:: StageOne :: new (
183
185
common_dir. as_deref ( ) . unwrap_or ( & git_dir) ,
184
186
git_dir. as_ref ( ) ,
185
- git_dir_trust,
187
+ * git_dir_trust,
186
188
lossy_config,
187
189
lenient_config,
188
190
) ?;
@@ -248,56 +250,6 @@ impl ThreadSafeRepository {
248
250
cli_config_overrides,
249
251
) ?;
250
252
251
- // TODO: Testing - it's hard to get non-ownership reliably and without root.
252
- // For now tested manually with https://github.com/GitoxideLabs/gitoxide/issues/1912
253
- if git_dir_trust != gix_sec:: Trust :: Full {
254
- let safe_dirs: Vec < BString > = config
255
- . resolved
256
- . strings_filter ( Safe :: DIRECTORY , & mut Safe :: directory_filter)
257
- . unwrap_or_default ( )
258
- . into_iter ( )
259
- . map ( Cow :: into_owned)
260
- . collect ( ) ;
261
- if bail_if_untrusted {
262
- check_safe_directories (
263
- & git_dir,
264
- git_install_dir. as_deref ( ) ,
265
- current_dir,
266
- home. as_deref ( ) ,
267
- & safe_dirs,
268
- ) ?;
269
- }
270
- let Ok ( mut resolved) = gix_features:: threading:: OwnShared :: try_unwrap ( config. resolved ) else {
271
- unreachable ! ( "Shared ownership was just established, with one reference" )
272
- } ;
273
- let section_ids: Vec < _ > = resolved. section_ids ( ) . collect ( ) ;
274
- for id in section_ids {
275
- let Some ( mut section) = resolved. section_mut_by_id ( id) else {
276
- continue ;
277
- } ;
278
- let section_trusted_by_default = Safe :: directory_filter ( section. meta ( ) ) ;
279
- if section_trusted_by_default || section. meta ( ) . trust == gix_sec:: Trust :: Full {
280
- continue ;
281
- }
282
- let Some ( meta_path) = section. meta ( ) . path . as_deref ( ) else {
283
- continue ;
284
- } ;
285
- let config_file_is_safe = check_safe_directories (
286
- meta_path,
287
- git_install_dir. as_deref ( ) ,
288
- current_dir,
289
- home. as_deref ( ) ,
290
- & safe_dirs,
291
- )
292
- . is_ok ( ) ;
293
-
294
- if config_file_is_safe {
295
- section. set_trust ( gix_sec:: Trust :: Full ) ;
296
- }
297
- }
298
- config. resolved = resolved. into ( ) ;
299
- }
300
-
301
253
// core.worktree might be used to overwrite the worktree directory
302
254
if !config. is_bare {
303
255
let mut key_source = None ;
@@ -384,6 +336,83 @@ impl ThreadSafeRepository {
384
336
}
385
337
}
386
338
339
+ // TODO: Testing - it's hard to get non-ownership reliably and without root.
340
+ // For now tested manually with https://github.com/GitoxideLabs/gitoxide/issues/1912
341
+ if * git_dir_trust != gix_sec:: Trust :: Full
342
+ || worktree_dir
343
+ . as_deref ( )
344
+ . is_some_and ( |wd| !gix_sec:: identity:: is_path_owned_by_current_user ( wd) . unwrap_or ( false ) )
345
+ {
346
+ let safe_dirs: Vec < BString > = config
347
+ . resolved
348
+ . strings_filter ( Safe :: DIRECTORY , & mut Safe :: directory_filter)
349
+ . unwrap_or_default ( )
350
+ . into_iter ( )
351
+ . map ( Cow :: into_owned)
352
+ . collect ( ) ;
353
+ let test_dir = worktree_dir. as_deref ( ) . unwrap_or ( git_dir. as_path ( ) ) ;
354
+ let res = check_safe_directories (
355
+ test_dir,
356
+ git_install_dir. as_deref ( ) ,
357
+ current_dir,
358
+ home. as_deref ( ) ,
359
+ & safe_dirs,
360
+ ) ;
361
+ if res. is_ok ( ) {
362
+ * git_dir_trust = gix_sec:: Trust :: Full ;
363
+ } else if bail_if_untrusted {
364
+ res?;
365
+ } else {
366
+ // This is how the worktree-trust can reduce the git-dir trust.
367
+ * git_dir_trust = gix_sec:: Trust :: Reduced ;
368
+ }
369
+
370
+ let Ok ( mut resolved) = gix_features:: threading:: OwnShared :: try_unwrap ( config. resolved ) else {
371
+ unreachable ! ( "Shared ownership was just established, with one reference" )
372
+ } ;
373
+ let section_ids: Vec < _ > = resolved. section_ids ( ) . collect ( ) ;
374
+ let mut is_valid_by_path = BTreeMap :: new ( ) ;
375
+ for id in section_ids {
376
+ let Some ( mut section) = resolved. section_mut_by_id ( id) else {
377
+ continue ;
378
+ } ;
379
+ let section_trusted_by_default = Safe :: directory_filter ( section. meta ( ) ) ;
380
+ if section_trusted_by_default || section. meta ( ) . trust == gix_sec:: Trust :: Full {
381
+ continue ;
382
+ }
383
+ let Some ( meta_path) = section. meta ( ) . path . as_deref ( ) else {
384
+ continue ;
385
+ } ;
386
+ match is_valid_by_path. entry ( meta_path. to_owned ( ) ) {
387
+ Entry :: Occupied ( entry) => {
388
+ if * entry. get ( ) {
389
+ section. set_trust ( gix_sec:: Trust :: Full ) ;
390
+ } else {
391
+ continue ;
392
+ }
393
+ }
394
+ Entry :: Vacant ( entry) => {
395
+ let config_file_is_safe = ( meta_path. strip_prefix ( test_dir) . is_ok ( )
396
+ && * git_dir_trust == gix_sec:: Trust :: Full )
397
+ || check_safe_directories (
398
+ meta_path,
399
+ git_install_dir. as_deref ( ) ,
400
+ current_dir,
401
+ home. as_deref ( ) ,
402
+ & safe_dirs,
403
+ )
404
+ . is_ok ( ) ;
405
+
406
+ entry. insert ( config_file_is_safe) ;
407
+ if config_file_is_safe {
408
+ section. set_trust ( gix_sec:: Trust :: Full ) ;
409
+ }
410
+ }
411
+ }
412
+ }
413
+ config. resolved = resolved. into ( ) ;
414
+ }
415
+
387
416
refs. write_reflog = config:: cache:: util:: reflog_or_default ( config. reflog , worktree_dir. is_some ( ) ) ;
388
417
refs. namespace . clone_from ( & config. refs_namespace ) ;
389
418
let prefix = replacement_objects_refs_prefix ( & config. resolved , lenient_config, filter_config_section) ?;
0 commit comments