98286406 Andy McCall 1 month ago ↶
1
2
1ec6fdbc Andy McCall 16 days ago ↶
3
use super :: tags:: TagCheck;
98286406 Andy McCall 1 month ago ↶
4
use super :: * ;
5
7aa2dc93 Andy McCall 1 month ago ↶
6
7
# [ derive ( Clone, Debug, Default ) ]
8
pub struct PushReport {
9
pub results : Vec< RefResult> ,
10
11
pub updated : Vec< RefUpdated> ,
12
13
pub imported : Vec< ChangeHash> ,
14
}
15
16
# [ derive ( Clone, Debug ) ]
17
pub struct RefUpdated {
18
pub name : String,
19
pub old_state : ObjectRef,
20
pub new_state : ObjectRef,
21
pub heads : Vec< ChangeHash> ,
22
}
23
83e0677b Andy McCall 1 month ago ↶
24
25
# [ derive ( Debug, Clone, PartialEq, Eq, Default ) ]
26
pub struct FetchReport {
27
28
pub refs : Vec< ( String, Vec< ChangeHash> , usize ) > ,
132b884b Andy McCall 1 month ago ↶
29
30
pub new_tags : usize ,
b63fc7a7 Andy McCall 11 days ago ↶
31
32
pub withdrawn_tags : Vec< String> ,
83e0677b Andy McCall 1 month ago ↶
33
34
35
pub unverified : bool ,
4b9d0677 Andy McCall 18 days ago ↶
36
37
38
39
pub log_notes : Vec< String> ,
d36ba2f7 Andy McCall 16 days ago ↶
40
41
42
43
44
pub skipped : Vec< ( String, String) > ,
83e0677b Andy McCall 1 month ago ↶
45
}
46
98286406 Andy McCall 1 month ago ↶
47
# [ derive ( Debug, Clone, PartialEq, Eq ) ]
48
pub struct PullReport {
14edbaaf Andy McCall 1 month ago ↶
49
98286406 Andy McCall 1 month ago ↶
50
pub heads : Vec< ChangeHash> ,
14edbaaf Andy McCall 1 month ago ↶
51
98286406 Andy McCall 1 month ago ↶
52
pub changed : bool ,
53
pub checked_out : bool ,
14edbaaf Andy McCall 1 month ago ↶
54
55
56
pub others : Vec< String> ,
d36ba2f7 Andy McCall 16 days ago ↶
57
58
pub skipped : Vec< ( String, String) > ,
98286406 Andy McCall 1 month ago ↶
59
}
60
cb8b8082 Andy McCall 26 days ago ↶
61
62
63
pub const OBJECTS_RESULT : & str = " objects" ;
64
98286406 Andy McCall 1 month ago ↶
65
impl Repo {
66
67
68
fn ref_attest_path ( & self , bookmark : & str ) -> PathBuf {
54cd08a1 Andy McCall 1 month ago ↶
69
self .oxy.join ( " attest" ) .join ( name_file ( bookmark) )
98286406 Andy McCall 1 month ago ↶
70
}
71
72
73
pub fn latest_ref_attest ( & self , bookmark : & str ) -> Result< Option< ( ObjectRef, SignedAttest) > > {
74
match fs:: read_to_string( self .ref_attest_path ( bookmark) ) {
75
Ok ( h) => {
75167672 Andy McCall 1 month ago
76
let r = ObjectRef:: from_hex( h.trim ( ) )
77
.ok_or_else ( | | RepoError:: Msg( " corrupt attestation pointer" .into ( ) ) ) ? ;
78
Ok ( Some ( (
79
r,
80
SignedAttest {
81
attest: self .store.get_attest ( & r) ? ,
82
sigs: self .store.signatures ( & r) ? ,
83
} ,
84
) ) )
98286406 Andy McCall 1 month ago ↶
85
}
86
Err ( e) if e.kind ( ) = = std:: io:: ErrorKind:: NotFound => Ok ( None ) ,
87
Err ( e) => Err ( e.into ( ) ) ,
88
}
89
}
90
9f9e72b9 Andy McCall 1 month ago ↶
91
pub ( crate ) fn set_ref_attest ( & self , bookmark : & str , r : & ObjectRef) -> Result< ( ) > {
98286406 Andy McCall 1 month ago ↶
92
fs:: create_dir_all( self .oxy.join ( " attest" ) ) ? ;
93
write_atomic ( & self .ref_attest_path ( bookmark) , r.to_hex ( ) .as_bytes ( ) )
94
}
95
83e0677b Andy McCall 1 month ago ↶
96
pub fn remote_refs ( & self ) -> Result< RefsResponse> {
98286406 Andy McCall 1 month ago ↶
97
let view = self .view ( ) ? ;
98
let mut out = Vec :: new( ) ;
99
for ( name, state) in & view.bookmarks {
100
let latest = self .latest_ref_attest ( name) ? .map ( | ( _, a ) | a ) ;
101
let last_serial = latest.as_ref ( ) .and_then ( | a | match a.attest.body {
102
AttestBody:: Ref { serial, .. } => Some ( serial) ,
103
_ => None ,
104
} ) ;
105
let attestation = latest.filter ( | a | matches! ( & a.attest.body, AttestBody:: Ref { new_state, .. } if new_state = = state) ) ;
f53cbe7a Andy McCall 18 days ago ↶
106
let accepted = match & attestation {
107
Some ( a) => self .acceptance_of ( & a.attest.hash ( ) ) ? ,
108
None => None ,
109
} ;
75167672 Andy McCall 1 month ago
110
out.push ( RemoteRef {
111
name: name.clone ( ) ,
112
state: * state,
113
heads: self .store.get_state ( state) ? .heads,
114
attestation,
115
last_serial,
f53cbe7a Andy McCall 18 days ago ↶
116
accepted,
4b9d0677 Andy McCall 18 days ago ↶
117
logged: None ,
028545df Andy McCall 17 days ago ↶
118
integration: vec! [ ] ,
75167672 Andy McCall 1 month ago
119
} ) ;
98286406 Andy McCall 1 month ago ↶
120
}
28fc23d7 Andy McCall 1 month ago ↶
121
let policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp ) ;
75167672 Andy McCall 1 month ago
122
let history = self
123
.policy_history ( ) ?
124
.into_iter ( )
125
.filter ( | sp | {
126
policy
127
.as_ref ( )
128
.is_some_and ( | p | sp.policy.serial < p.policy.serial )
129
} )
130
.collect ( ) ;
131
Ok ( RefsResponse {
132
refs: out,
133
policy,
134
tags: self .tag_refs ( ) ? ,
135
history,
14edbaaf Andy McCall 1 month ago ↶
136
default_bookmark: Some ( self .config.bookmark.clone ( ) ) ,
4b9d0677 Andy McCall 18 days ago ↶
137
log: None ,
028545df Andy McCall 17 days ago ↶
138
witnesses: vec! [ ] ,
b63fc7a7 Andy McCall 11 days ago ↶
139
withdrawn: self .withdrawn_refs ( ) ? ,
75167672 Andy McCall 1 month ago
140
} )
98286406 Andy McCall 1 month ago ↶
141
}
142
143
144
fn closure_in_store ( & self , heads : & [ChangeHash]) -> Result< BTreeSet< ChangeHash> > {
145
let mut seen = BTreeSet:: new( ) ;
146
let mut stack: Vec< ChangeHash> = heads.to_vec ( ) ;
147
while let Some ( h) = stack.pop ( ) {
148
if seen.contains ( & h) | | ! self .store.has ( & h) {
149
continue ;
150
}
151
seen.insert ( h) ;
69816d68 Andy McCall 1 month ago ↶
152
stack.extend ( self .store.get_change_meta ( & h) ? .deps) ;
98286406 Andy McCall 1 month ago ↶
153
}
154
Ok ( seen)
155
}
156
2863456a Andy McCall 1 month ago ↶
157
158
159
pub fn shallow_changes ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
160
let mut out = Vec :: new( ) ;
161
let mut seen: BTreeSet< ChangeHash> = BTreeSet:: new( ) ;
162
let mut layer: Vec< ChangeHash> = heads.to_vec ( ) ;
163
for _ in 0 .. depth.max ( 1 ) {
164
let mut next = Vec :: new( ) ;
165
for h in layer {
166
if ! seen.insert ( h) | | ! self .store.has ( & h) {
167
continue ;
168
}
169
let c = self .store.get_change ( & h) ? ;
170
next.extend ( c.deps.iter ( ) .copied ( ) ) ;
171
out.push ( h) ;
172
}
173
if next.is_empty ( ) {
174
break ;
175
}
176
layer = next;
177
}
178
out.reverse ( ) ;
179
Ok ( out)
180
}
181
182
fn shallow_path ( & self ) -> PathBuf {
183
self .oxy.join ( " shallow" )
184
}
185
186
187
pub fn boundary ( & self ) -> BTreeSet< ChangeHash> {
75167672 Andy McCall 1 month ago
188
fs:: read_to_string( self .shallow_path ( ) )
189
.map ( | t | t.lines ( ) .filter_map ( ObjectRef:: from_hex) .collect ( ) )
190
.unwrap_or_default ( )
2863456a Andy McCall 1 month ago ↶
191
}
192
193
pub fn is_shallow ( & self ) -> bool {
194
! self .boundary ( ) .is_empty ( )
195
}
196
197
fn write_boundary ( & self , boundary : & BTreeSet< ChangeHash> ) -> Result< ( ) > {
198
if boundary.is_empty ( ) {
199
let _ = fs:: remove_file( self .shallow_path ( ) ) ;
200
return Ok ( ( ) ) ;
201
}
75167672 Andy McCall 1 month ago
202
let text: String = boundary
203
.iter ( )
204
.map ( | h | format! ( " {} \n " , h.to_hex ( ) ) )
205
.collect ( ) ;
2863456a Andy McCall 1 month ago ↶
206
write_atomic ( & self .shallow_path ( ) , text.as_bytes ( ) )
207
}
208
209
210
211
fn refresh_boundary ( & self , imported : & [ChangeHash]) -> Result< ( ) > {
212
let mut boundary = self .boundary ( ) ;
213
boundary.retain ( | h | ! self .store.has ( h) ) ;
214
for h in imported {
69816d68 Andy McCall 1 month ago ↶
215
for d in self .store.get_change_meta ( h) ? .deps {
2863456a Andy McCall 1 month ago ↶
216
if ! self .store.has ( & d) {
217
boundary.insert ( d) ;
218
}
219
}
220
}
221
self .write_boundary ( & boundary)
222
}
223
224
225
pub fn deepen ( & self , remote_name : & str , depth : u32 ) -> Result< usize > {
226
let boundary = self .boundary ( ) ;
227
if boundary.is_empty ( ) {
228
return Ok ( 0 ) ;
229
}
230
let remote = self .open_named_remote ( remote_name) ? ;
231
let wanted = remote.shallow ( & boundary.iter ( ) .copied ( ) .collect:: < Vec< _ > > ( ) , depth) ? ;
232
let bundle = remote.fetch ( & wanted, self .config.max_blob) ? ;
233
let imported = self .import_bundle_shallow ( & bundle, false ) ? ;
234
if self .config.max_blob.is_some ( ) {
235
self .register_missing_blobs ( & imported, remote_name) ? ;
236
}
237
self .refresh_boundary ( & imported) ? ;
238
Ok ( imported.len ( ) )
239
}
240
98286406 Andy McCall 1 month ago ↶
241
242
pub fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
243
let have = self .closure_in_store ( have) ? ;
2863456a Andy McCall 1 month ago ↶
244
245
246
let boundary = self .boundary ( ) ;
98286406 Andy McCall 1 month ago ↶
247
let mut out = Vec :: new( ) ;
248
let mut done: BTreeSet< ChangeHash> = have.clone ( ) ;
2863456a Andy McCall 1 month ago ↶
249
done.extend ( boundary.iter ( ) .copied ( ) ) ;
98286406 Andy McCall 1 month ago ↶
250
f3811eb2 Andy McCall 11 days ago ↶
251
let shallow = self .is_shallow ( ) ;
98286406 Andy McCall 1 month ago ↶
252
let mut stack: Vec< ( ChangeHash, bool ) > = want.iter ( ) .rev ( ) .map ( | h | ( * h, false ) ) .collect ( ) ;
253
while let Some ( ( h, expanded) ) = stack.pop ( ) {
254
if done.contains ( & h) {
255
continue ;
256
}
257
if ! self .store.has ( & h) {
f3811eb2 Andy McCall 11 days ago ↶
258
259
260
261
262
if shallow {
263
done.insert ( h) ;
264
continue ;
265
}
98286406 Andy McCall 1 month ago ↶
266
return fail ( format! ( " change {} is not in this repository" , h.short ( 12 ) ) ) ;
267
}
268
if expanded {
269
done.insert ( h) ;
270
out.push ( h) ;
271
continue ;
272
}
273
stack.push ( ( h, true ) ) ;
69816d68 Andy McCall 1 month ago ↶
274
for d in self .store.get_change_meta ( & h) ? .deps {
98286406 Andy McCall 1 month ago ↶
275
if ! done.contains ( & d) {
276
stack.push ( ( d, false ) ) ;
277
}
278
}
279
}
280
Ok ( out)
281
}
282
283
284
285
pub fn bundle_for ( & self , changes : & [ChangeHash]) -> Result< Bundle> {
d36ba2f7 Andy McCall 16 days ago ↶
286
self .bundle_of ( changes, None , false , false )
b3c5a59a Andy McCall 1 month ago ↶
287
}
288
289
290
pub fn objects_for ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
291
let mut out = Vec :: new( ) ;
292
for r in refs {
293
let ( ty, body) = match self .store.get ( r) {
294
Ok ( x) => x,
295
Err ( StoreError:: NotFound( _ ) ) => continue ,
296
Err ( e) => return Err ( e.into ( ) ) ,
297
} ;
298
if ty = = ObjectType:: Blob {
299
for c in Blob:: decode( & body) ? .chunks {
300
if let Ok ( ( cty, cb) ) = self .store.get ( & c) {
301
out.push ( ( cty, cb) ) ;
302
}
303
}
304
}
305
out.push ( ( ty, body) ) ;
306
}
307
Ok ( out)
308
}
309
310
311
d36ba2f7 Andy McCall 16 days ago ↶
312
313
314
315
75167672 Andy McCall 1 month ago
316
pub fn bundle_for_filtered (
317
& self ,
318
changes : & [ChangeHash],
319
max_blob : Option< u64 > ,
320
) -> Result< Bundle> {
d36ba2f7 Andy McCall 16 days ago ↶
321
self .bundle_of ( changes, max_blob, false , true )
2c75672f Andy McCall 1 month ago ↶
322
}
323
324
325
326
327
328
pub fn bundle_raw_for ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
d36ba2f7 Andy McCall 16 days ago ↶
329
self .bundle_of ( changes, max_blob, true , true )
2c75672f Andy McCall 1 month ago ↶
330
}
331
d36ba2f7 Andy McCall 16 days ago ↶
332
333
334
335
336
337
e10ba800 Andy McCall 16 days ago ↶
338
339
340
341
342
d36ba2f7 Andy McCall 16 days ago ↶
343
pub fn served_attest_signers ( & self ) -> Result< BTreeSet< KeyId> > {
e10ba800 Andy McCall 16 days ago ↶
344
type Signers = std:: collections:: HashMap< ( PathBuf, ObjectRef) , BTreeSet< KeyId> > ;
345
static SERVED : std:: sync:: Mutex< Option< Signers> > = std:: sync:: Mutex:: new( None ) ;
346
let key = ( self .oxy.clone ( ) , self .head_op ( ) ? .0 ) ;
347
if let Some ( keys) = SERVED
348
.lock ( )
349
.unwrap_or_else ( | p | p.into_inner ( ) )
350
.as_ref ( )
351
.and_then ( | m | m.get ( & key) )
352
{
353
return Ok ( keys.clone ( ) ) ;
354
}
355
let keys = self .attest_signers_now ( ) ? ;
356
let mut served = SERVED .lock ( ) .unwrap_or_else ( | p | p.into_inner ( ) ) ;
357
let map = served.get_or_insert_with ( Default :: default) ;
358
359
360
map.retain ( | ( oxy , _) , _| * oxy ! = key.0 ) ;
361
if map.len ( ) > = 1024 {
362
map.clear ( ) ;
363
}
364
map.insert ( key, keys.clone ( ) ) ;
365
Ok ( keys)
366
}
367
368
fn attest_signers_now ( & self ) -> Result< BTreeSet< KeyId> > {
d36ba2f7 Andy McCall 16 days ago ↶
369
let view = self .view ( ) ? ;
370
let pointers = view
371
.bookmarks
372
.keys ( )
373
.map ( | b | self .ref_attest_path ( b) )
374
.chain ( view.tags.keys ( ) .map ( | t | self .tag_attest_path ( t) ) ) ;
375
let mut keys = BTreeSet:: new( ) ;
376
for p in pointers {
377
let Ok ( text) = fs:: read_to_string( & p) else {
378
continue ;
379
} ;
380
let Some ( r) = ObjectRef:: from_hex( text.trim ( ) ) else {
381
continue ;
382
} ;
383
keys.extend ( self .store.signatures ( & r) ? .into_iter ( ) .map ( | s | s.key ) ) ;
384
}
385
Ok ( keys)
386
}
387
388
389
2c75672f Andy McCall 1 month ago ↶
390
fn bundle_of (
391
& self ,
392
changes : & [ChangeHash],
393
max_blob : Option< u64 > ,
394
raw : bool ,
d36ba2f7 Andy McCall 16 days ago ↶
395
serving : bool ,
2c75672f Andy McCall 1 month ago ↶
396
) -> Result< Bundle> {
98286406 Andy McCall 1 month ago ↶
397
let mut bundle = Bundle:: default( ) ;
398
let mut objects: BTreeSet< ObjectRef> = BTreeSet:: new( ) ;
399
let mut seals: BTreeSet< ObjectRef> = BTreeSet:: new( ) ;
400
let add_object = | r : & ObjectRef, objects : & mut BTreeSet< ObjectRef> | {
401
if ! r.is_zero ( ) & & self .store.has ( r) {
402
objects.insert ( * r) ;
403
}
404
} ;
405
for h in changes {
2c75672f Andy McCall 1 month ago ↶
406
407
let ( c, encoded) = if raw {
408
let bytes = self .store.get_typed ( h, ObjectType:: Change) ? ;
409
let ( skel, texts) = Change:: decode_skeleton( & bytes, * h) ? ;
410
for t in texts {
0f93f49c Andy McCall 1 month ago ↶
411
if let crate :: objects:: TextRef:: Blob( r, _ , _ ) = t {
2c75672f Andy McCall 1 month ago ↶
412
let blob = Blob:: decode( & self .store.get_typed ( & r, ObjectType:: Blob) ? ) ? ;
413
objects.insert ( r) ;
414
objects.extend ( blob.chunks) ;
415
}
416
}
417
( skel, Some ( bytes) )
418
} else {
419
( self .store.get_change ( h) ? , None )
420
} ;
98286406 Andy McCall 1 month ago ↶
421
let sigs = self .store.signatures ( h) ? ;
422
add_object ( & c.author, & mut objects) ;
423
for s in & sigs {
424
add_object ( & s.key, & mut objects) ;
425
}
570e3531 Andy McCall 11 days ago ↶
426
427
428
429
98286406 Andy McCall 1 month ago ↶
430
for e in & c.edits {
570e3531 Andy McCall 11 days ago ↶
431
if let Edit:: Replace { new: Some ( b) , .. } = e {
432
if self .store.has ( b) {
433
if let Ok ( blob) = Blob:: decode( & self .store.get_typed ( b, ObjectType:: Blob) ? )
434
{
435
if max_blob.is_some_and ( | m | blob.length > m ) {
436
continue ;
98286406 Andy McCall 1 month ago ↶
437
}
570e3531 Andy McCall 11 days ago ↶
438
objects.insert ( * b) ;
439
objects.extend ( blob.chunks.iter ( ) .copied ( ) ) ;
98286406 Andy McCall 1 month ago ↶
440
}
441
}
442
}
443
}
444
for s in self .store.seals_for ( h) ? {
445
seals.insert ( s) ;
2c75672f Andy McCall 1 month ago ↶
446
}
447
match encoded {
448
Some ( bytes) => bundle.raw_changes.push ( ( bytes, sigs) ) ,
449
None => {
450
bundle.changes.push ( ( c, sigs) ) ;
451
bundle.hashes.push ( * h) ;
452
}
98286406 Andy McCall 1 month ago ↶
453
}
454
}
455
for r in seals {
456
let attest = self .store.get_attest ( & r) ? ;
457
let sigs = self .store.signatures ( & r) ? ;
458
for s in & sigs {
459
add_object ( & s.key, & mut objects) ;
460
}
461
bundle.attests.push ( SignedAttest { attest, sigs } ) ;
462
}
d36ba2f7 Andy McCall 16 days ago ↶
463
let signers: Vec< KeyId> = if serving {
464
let signers = self .served_attest_signers ( ) ? ;
465
for k in & signers {
466
add_object ( k, & mut objects) ;
467
}
468
signers.into_iter ( ) .collect ( )
469
} else {
470
Vec :: new( )
471
} ;
98286406 Andy McCall 1 month ago ↶
472
for r in objects {
473
let ( ty, body) = self .store.get ( & r) ? ;
474
bundle.objects.push ( ( ty, body) ) ;
475
}
d36ba2f7 Andy McCall 16 days ago ↶
476
self .attach_certificates_for ( & mut bundle, & signers) ? ;
98286406 Andy McCall 1 month ago ↶
477
Ok ( bundle)
478
}
479
f0a517d2 Andy McCall 18 days ago ↶
480
481
482
483
484
pub ( crate ) fn attach_certificates_for (
485
& self ,
486
bundle : & mut Bundle,
487
also : & [KeyId],
488
) -> Result< ( ) > {
489
let mut keys: BTreeSet< KeyId> = also.iter ( ) .copied ( ) .collect ( ) ;
490
keys.extend (
491
bundle
492
.changes
493
.iter ( )
494
.flat_map ( | ( _, s ) | s.iter ( ) .map ( | s | s.key ) ) ,
495
) ;
496
keys.extend (
497
bundle
498
.raw_changes
499
.iter ( )
500
.flat_map ( | ( _, s ) | s.iter ( ) .map ( | s | s.key ) ) ,
501
) ;
502
keys.extend (
503
bundle
504
.attests
505
.iter ( )
506
.flat_map ( | a | a.sigs.iter ( ) .map ( | s | s.key ) ) ,
507
) ;
508
for k in keys {
509
let Some ( r) = self .store.certificate_of ( & k) ? else {
510
continue ;
511
} ;
512
let cert = self .store.get_certificate ( & r) ? ;
513
if bundle
514
.certificates
515
.iter ( )
516
.any ( | c | c.cert.hash ( ) = = cert.cert.hash ( ) )
517
{
518
continue ;
519
}
f0ef9778 Andy McCall 11 days ago ↶
520
521
522
let grantor = cert.cert.grant.as_ref ( ) .map ( | g | g.grant.grantor ) ;
523
for id in [ Some ( k) , Some ( cert.cert.issuer) , grantor] .iter ( ) .flatten ( ) {
f0a517d2 Andy McCall 18 days ago ↶
524
if let Ok ( body) = self .store.get_typed ( id, ObjectType:: Identity) {
525
if ! bundle
526
.objects
527
.iter ( )
528
.any ( | ( t , b ) | * t = = ObjectType:: Identity & & * b = = body)
529
{
530
bundle.objects.push ( ( ObjectType:: Identity, body) ) ;
531
}
532
}
533
}
534
bundle.certificates.push ( cert) ;
535
}
536
Ok ( ( ) )
537
}
538
539
540
541
fn adopt_certificates ( & self , certs : & [crate:: cert:: SignedCertificate]) -> Result< ( ) > {
542
for c in certs {
543
let issuer = self .store.get_identity ( & c.cert.issuer) .map_err ( | _| {
544
RepoError:: Msg( format! (
545
" a certificate names issuer {} , whose identity did not come with it" ,
546
c.cert.issuer.short ( 12 )
547
) )
548
} ) ? ;
549
c.verify ( & issuer)
550
.map_err ( | e | RepoError:: Msg( format! ( " a certificate does not verify: {e} " ) ) ) ? ;
551
self .store.put_identity ( & c.cert.key) ? ;
552
self .store.put_certificate ( c) ? ;
553
}
554
Ok ( ( ) )
555
}
556
557
558
559
560
561
pub ( crate ) fn certified_authorized (
562
& self ,
563
p : & crate:: policy:: Policy,
564
signer : & KeyId,
565
reference : & str ,
566
scope : Scope,
567
at_ms : u64 ,
568
) -> bool {
569
let Ok ( Some ( r) ) = self .store.certificate_of ( signer) else {
570
return false ;
571
} ;
572
let Ok ( c) = self .store.get_certificate ( & r) else {
573
return false ;
574
} ;
575
let Some ( issuer) = p
576
.identity ( & c.cert.issuer)
577
.cloned ( )
578
.or_else ( | | self .store.get_identity ( & c.cert.issuer) .ok ( ) )
579
else {
580
return false ;
581
} ;
582
c.verify ( & issuer) .is_ok ( )
583
& & c.cert.key_id ( ) = = * signer
584
& & c.cert.covers ( scope, at_ms)
585
& & p.subject_grant ( reference, & c.cert.issuer, & c.cert.subject, scope)
586
}
587
98286406 Andy McCall 1 month ago ↶
588
589
590
pub fn import_bundle ( & self , bundle : & Bundle, strict : bool ) -> Result< Vec< ChangeHash> > {
2863456a Andy McCall 1 month ago ↶
591
self .import_bundle_inner ( bundle, strict, false )
592
}
593
594
595
596
pub fn import_bundle_shallow ( & self , bundle : & Bundle, strict : bool ) -> Result< Vec< ChangeHash> > {
597
self .import_bundle_inner ( bundle, strict, true )
598
}
599
75167672 Andy McCall 1 month ago
600
fn import_bundle_inner (
601
& self ,
602
bundle : & Bundle,
603
strict : bool ,
604
shallow : bool ,
605
) -> Result< Vec< ChangeHash> > {
8f10a07a Andy McCall 1 month ago ↶
606
let batch = self .store.begin_batch ( ) ? ;
607
let result = self .import_bundle_batched ( bundle, strict, shallow) ;
608
batch.finish ( ) ? ;
609
result
610
}
611
75167672 Andy McCall 1 month ago
612
fn import_bundle_batched (
613
& self ,
614
bundle : & Bundle,
615
strict : bool ,
616
shallow : bool ,
617
) -> Result< Vec< ChangeHash> > {
2c75672f Andy McCall 1 month ago ↶
618
for ( ty, _ ) in & bundle.objects {
619
if ! matches! (
620
ty,
75167672 Andy McCall 1 month ago
621
ObjectType:: Chunk
2c75672f Andy McCall 1 month ago ↶
622
| ObjectType:: Blob
623
| ObjectType:: Identity
624
| ObjectType:: State
625
| ObjectType:: Checkpoint
626
) {
627
return fail ( format! ( " bundle may not carry {} objects" , ty.name ( ) ) ) ;
98286406 Andy McCall 1 month ago ↶
628
}
629
}
2c75672f Andy McCall 1 month ago ↶
630
631
let objects: Vec< ( ObjectType, & [u8 ]) > = bundle
632
.objects
633
.iter ( )
634
.map ( | ( ty , body ) | ( * ty, body.as_slice ( ) ) )
635
.collect ( ) ;
636
self .store.put_many ( & objects) ? ;
f0a517d2 Andy McCall 18 days ago ↶
637
self .adopt_certificates ( & bundle.certificates) ? ;
98286406 Andy McCall 1 month ago ↶
638
for sa in & bundle.attests {
639
let r = self .store.put_attest ( & sa.attest) ? ;
640
for sig in & sa.sigs {
641
self .store.put_signature ( & r, sig) ? ;
642
}
643
if let AttestBody:: Seal { hashes } = & sa.attest.body {
644
for h in hashes {
645
self .store.index_seal ( h, & r) ? ;
646
}
647
}
648
}
598009a7 Andy McCall 1 month ago ↶
649
650
651
652
let hashes: Vec< ChangeHash> = if bundle.hashes.len ( ) = = bundle.changes.len ( ) {
653
bundle.hashes.clone ( )
654
} else {
655
bundle.changes.iter ( ) .map ( | ( c , _) | c.hash ( ) ) .collect ( )
656
} ;
2c75672f Andy McCall 1 month ago ↶
657
let raw_hashes: Vec< ChangeHash> = bundle
658
.raw_changes
659
.iter ( )
660
.map ( | ( b , _) | hash_object ( ObjectType:: Change, b) )
661
.collect ( ) ;
662
let incoming: BTreeSet< ChangeHash> = hashes.iter ( ) .chain ( & raw_hashes) .copied ( ) .collect ( ) ;
2863456a Andy McCall 1 month ago ↶
663
let boundary = self .boundary ( ) ;
98286406 Andy McCall 1 month ago ↶
664
let mut imported = Vec :: new( ) ;
2c75672f Andy McCall 1 month ago ↶
665
666
667
for ( ( bytes, sigs) , h) in bundle.raw_changes.iter ( ) .zip ( raw_hashes) {
668
let ( skel, texts) = Change:: decode_skeleton( bytes, h) ? ;
669
for d in & skel.deps {
670
if ! self .store.has ( d) & & ! incoming.contains ( d) & & ! shallow & & ! boundary.contains ( d)
671
{
672
return fail ( format! (
673
" change {} depends on {} , which is neither stored nor in the bundle" ,
674
h.short ( 12 ) ,
675
d.short ( 12 )
676
) ) ;
677
}
678
}
679
for t in texts {
0f93f49c Andy McCall 1 month ago ↶
680
if let crate :: objects:: TextRef:: Blob( r, _ , _ ) = t {
2c75672f Andy McCall 1 month ago ↶
681
if ! self .store.has ( & r) {
682
return fail ( format! (
683
" change {} came without its text blob {} " ,
684
h.short ( 12 ) ,
685
r.short ( 12 )
686
) ) ;
687
}
688
}
689
}
690
self .store.put ( ObjectType:: Change, bytes) ? ;
691
for sig in sigs {
692
self .store.put_signature ( & h, sig) ? ;
693
}
694
imported.push ( h) ;
695
}
598009a7 Andy McCall 1 month ago ↶
696
for ( ( c, sigs) , h) in bundle.changes.iter ( ) .zip ( hashes) {
98286406 Andy McCall 1 month ago ↶
697
for d in & c.deps {
75167672 Andy McCall 1 month ago
698
if ! self .store.has ( d) & & ! incoming.contains ( d) & & ! shallow & & ! boundary.contains ( d)
699
{
700
return fail ( format! (
701
" change {} depends on {} , which is neither stored nor in the bundle" ,
702
h.short ( 12 ) ,
703
d.short ( 12 )
704
) ) ;
98286406 Andy McCall 1 month ago ↶
705
}
706
}
598009a7 Andy McCall 1 month ago ↶
707
let stored = self .store.put_change ( c) ? ;
708
if stored ! = h {
709
return fail ( format! (
710
" change {} is not the change the bundle names" ,
711
h.short ( 12 )
712
) ) ;
713
}
98286406 Andy McCall 1 month ago ↶
714
for sig in sigs {
715
self .store.put_signature ( & h, sig) ? ;
716
}
717
imported.push ( h) ;
718
}
719
if strict {
720
for h in & imported {
721
if ! matches! ( self .authenticate_change ( h) ? , SignatureStatus:: Valid { .. } ) {
75167672 Andy McCall 1 month ago
722
return fail ( format! (
723
" change {} is not authenticated by its author" ,
724
h.short ( 12 )
725
) ) ;
98286406 Andy McCall 1 month ago ↶
726
}
727
}
728
}
729
Ok ( imported)
730
}
731
732
733
734
84b9e9ac Andy McCall 1 month ago ↶
735
736
7ba155f2 Andy McCall 1 month ago ↶
737
738
739
eae59556 Andy McCall 1 month ago ↶
740
pub ( crate ) fn delegate_authorized (
741
& self ,
742
p : & crate:: policy:: Policy,
743
signer : & KeyId,
744
reference : & str ,
7ba155f2 Andy McCall 1 month ago ↶
745
at_ms : u64 ,
eae59556 Andy McCall 1 month ago ↶
746
) -> bool {
84b9e9ac Andy McCall 1 month ago ↶
747
if p.is_revoked ( signer) {
748
return false ;
749
}
eae59556 Andy McCall 1 month ago ↶
750
let Some ( rule) = p.rule_for ( reference) else {
751
return false ;
752
} ;
84b9e9ac Andy McCall 1 month ago ↶
753
rule.keys.iter ( ) .any ( | k | {
754
! p.is_revoked ( k)
755
& & p.identity ( k)
756
.cloned ( )
757
.or_else ( | | self .store.get_identity ( k) .ok ( ) )
7ba155f2 Andy McCall 1 month ago ↶
758
.is_some_and ( | id | id.delegates_to ( signer, Scope:: REFS , at_ms) )
84b9e9ac Andy McCall 1 month ago ↶
759
} )
760
}
761
e5d9b051 Andy McCall 19 days ago ↶
762
763
764
765
766
767
768
pub ( crate ) fn predecessor_authorized (
769
& self ,
770
p : & crate:: policy:: Policy,
771
signer : & KeyId,
772
reference : & str ,
773
at_ms : u64 ,
774
) -> bool {
775
if p.is_revoked ( signer) {
776
return false ;
777
}
778
let Some ( rule) = p.rule_for ( reference) else {
779
return false ;
780
} ;
781
let identity = | k : & KeyId| {
782
p.identity ( k)
783
.cloned ( )
784
.or_else ( | | self .store.get_identity ( k) .ok ( ) )
785
} ;
786
rule.keys.iter ( ) .any ( | k | {
787
if p.is_revoked ( k) {
788
return false ;
789
}
790
let mut cur = identity ( k) ;
791
for _ in 0 .. 32 {
792
let Some ( id) = cur else {
793
return false ;
794
} ;
795
match id.previous {
796
Some ( prev) if prev = = * signer => return at_ms < id.created,
797
Some ( prev) if ! p.is_revoked ( & prev) => cur = identity ( & prev) ,
798
_ => return false ,
799
}
800
}
801
false
802
} )
803
}
804
75167672 Andy McCall 1 month ago
805
fn check_ref_attest (
d36ba2f7 Andy McCall 16 days ago ↶
806
& self ,
807
sa : & SignedAttest,
808
name : & str ,
809
old_state : & ObjectRef,
810
new_state : & ObjectRef,
811
last_serial : Option< u64 > ,
812
allow_equal : bool ,
813
) -> std:: result:: Result< u64 , String> {
814
let serial =
815
self .check_ref_attest_body ( sa, name, old_state, new_state, last_serial, allow_equal) ? ;
816
self .verify_attest_signature ( sa) ? ;
817
Ok ( serial)
818
}
819
820
821
822
823
fn check_ref_attest_body (
75167672 Andy McCall 1 month ago
824
& self ,
825
sa : & SignedAttest,
826
name : & str ,
827
old_state : & ObjectRef,
828
new_state : & ObjectRef,
829
last_serial : Option< u64 > ,
830
allow_equal : bool ,
831
) -> std:: result:: Result< u64 , String> {
832
let AttestBody:: Ref {
833
name: n,
834
old_state: o,
835
new_state: nw,
836
serial,
837
} = & sa.attest.body
838
else {
98286406 Andy McCall 1 month ago ↶
839
return Err ( " attestation is not a ref attestation" .into ( ) ) ;
840
} ;
841
if n ! = name | | o ! = old_state | | nw ! = new_state {
842
return Err ( " attestation does not describe this update" .into ( ) ) ;
843
}
844
if sa.attest.repo ! = self .id ( ) .map_err ( | e | e.to_string ( ) ) ? {
845
return Err ( " attestation is for a different repository" .into ( ) ) ;
846
}
847
if let Some ( last) = last_serial {
848
if * serial < last | | ( * serial = = last & & ! allow_equal) {
75167672 Andy McCall 1 month ago
849
return Err ( format! (
850
" attestation serial {serial} is not greater than the last seen {last} "
851
) ) ;
98286406 Andy McCall 1 month ago ↶
852
}
853
}
d36ba2f7 Andy McCall 16 days ago ↶
854
Ok ( * serial)
855
}
856
857
858
859
fn verify_attest_signature ( & self , sa : & SignedAttest) -> std:: result:: Result< ( ) , String> {
98286406 Andy McCall 1 month ago ↶
860
let r = sa.attest.hash ( ) ;
861
let sig = sa.sigs.first ( ) .ok_or ( " attestation carries no signature" ) ? ;
75167672 Andy McCall 1 month ago
862
let id = self
863
.store
864
.get_identity ( & sig.key)
865
.map_err ( | _| format! ( " unknown key {} " , sig.key.short ( 12 ) ) ) ? ;
d36ba2f7 Andy McCall 16 days ago ↶
866
verify_signature ( & id, sig, Domain:: Attest, & r) .map_err ( | e | e.to_string ( ) )
98286406 Andy McCall 1 month ago ↶
867
}
868
83e0677b Andy McCall 1 month ago ↶
869
98286406 Andy McCall 1 month ago ↶
870
83e0677b Andy McCall 1 month ago ↶
871
872
873
75167672 Andy McCall 1 month ago
874
pub fn receive_push (
875
& self ,
876
bundle : Bundle,
877
updates : Vec< RefUpdate> ,
878
policy : Option< SignedPolicy> ,
879
tags : Vec< crate:: protocol:: TagRef> ,
880
) -> Result< Vec< RefResult> > {
119bbf50 Andy McCall 1 month ago ↶
881
Ok ( self
882
.receive_push_report ( bundle, updates, policy, tags) ?
883
.results )
7aa2dc93 Andy McCall 1 month ago ↶
884
}
885
886
887
888
889
pub fn receive_push_report (
890
& self ,
891
bundle : Bundle,
892
updates : Vec< RefUpdate> ,
893
policy : Option< SignedPolicy> ,
894
tags : Vec< crate:: protocol:: TagRef> ,
895
) -> Result< PushReport> {
767ac6cd Andy McCall 17 days ago
896
897
898
899
self .refresh ( ) ? ;
7aa2dc93 Andy McCall 1 month ago ↶
900
let mut report = PushReport:: default( ) ;
901
let results = & mut report.results;
83e0677b Andy McCall 1 month ago ↶
902
if let Some ( sp) = policy {
28fc23d7 Andy McCall 1 month ago ↶
903
match self .adopt_policy_chain ( & bundle.policies, & sp, " push received" ) {
83e0677b Andy McCall 1 month ago ↶
904
Ok ( ( ) ) => {
75167672 Andy McCall 1 month ago
905
results.push ( RefResult {
906
name: " policy" .into ( ) ,
907
ok: true ,
908
reason: format! ( " serial {} " , sp.policy.serial) ,
909
} ) ;
83e0677b Andy McCall 1 month ago ↶
910
}
911
Err ( e) => {
75167672 Andy McCall 1 month ago
912
results.push ( RefResult {
913
name: " policy" .into ( ) ,
914
ok: false ,
915
reason: e,
916
} ) ;
83e0677b Andy McCall 1 month ago ↶
917
for u in updates {
75167672 Andy McCall 1 month ago
918
results.push ( RefResult {
919
name: u.name,
920
ok: false ,
921
reason: " policy update was rejected" .into ( ) ,
922
} ) ;
83e0677b Andy McCall 1 month ago ↶
923
}
7aa2dc93 Andy McCall 1 month ago ↶
924
return Ok ( report) ;
83e0677b Andy McCall 1 month ago ↶
925
}
926
}
927
}
928
let policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp.policy ) ;
cb8b8082 Andy McCall 26 days ago ↶
929
930
931
let objects_only = updates.is_empty ( ) & & tags.is_empty ( ) ;
7aa2dc93 Andy McCall 1 month ago ↶
932
match self .import_bundle ( & bundle, policy.is_some ( ) ) {
cb8b8082 Andy McCall 26 days ago ↶
933
Ok ( imported) => {
934
if objects_only {
935
results.push ( RefResult {
936
name: OBJECTS_RESULT .into ( ) ,
937
ok: true ,
938
reason: format! ( " {} changes stored" , imported.len ( ) ) ,
939
} ) ;
940
}
941
report.imported = imported;
942
}
7aa2dc93 Andy McCall 1 month ago ↶
943
Err ( e) => {
cb8b8082 Andy McCall 26 days ago ↶
944
if objects_only {
945
results.push ( RefResult {
946
name: OBJECTS_RESULT .into ( ) ,
947
ok: false ,
948
reason: e.to_string ( ) ,
949
} ) ;
950
}
7aa2dc93 Andy McCall 1 month ago ↶
951
for u in updates {
952
results.push ( RefResult {
953
name: u.name,
954
ok: false ,
955
reason: e.to_string ( ) ,
956
} ) ;
957
}
958
return Ok ( report) ;
83e0677b Andy McCall 1 month ago ↶
959
}
960
}
98286406 Andy McCall 1 month ago ↶
961
let ( op_ref, op) = self .head_op ( ) ? ;
962
let mut view = op.view.clone ( ) ;
963
let mut names = Vec :: new( ) ;
964
for u in updates {
83e0677b Andy McCall 1 month ago ↶
965
let outcome = self .apply_update ( & mut view, & u, policy.as_ref ( ) ) ;
98286406 Andy McCall 1 month ago ↶
966
let ( ok, reason) = match outcome {
967
Ok ( ( ) ) => ( true , String :: new( ) ) ,
968
Err ( e) => ( false , e) ,
969
} ;
970
if ok {
971
names.push ( u.name.clone ( ) ) ;
119bbf50 Andy McCall 1 month ago ↶
972
let heads = self
973
.store
974
.get_state ( & u.new_state)
975
.map ( | s | s.heads )
976
.unwrap_or_default ( ) ;
977
report.updated.push ( RefUpdated {
978
name: u.name.clone ( ) ,
979
old_state: u.old_state,
980
new_state: u.new_state,
981
heads,
982
} ) ;
98286406 Andy McCall 1 month ago ↶
983
}
75167672 Andy McCall 1 month ago
984
results.push ( RefResult {
985
name: u.name,
986
ok,
987
reason,
988
} ) ;
98286406 Andy McCall 1 month ago ↶
989
}
132b884b Andy McCall 1 month ago ↶
990
for t in & tags {
991
let name = format! ( " tags/{} " , t.name) ;
b63fc7a7 Andy McCall 11 days ago ↶
992
if t.is_withdrawal ( ) {
993
match self .adopt_withdrawal ( & mut view, t, policy.as_ref ( ) , & mut TagCheck:: Received)
994
{
995
Ok ( removed) => {
996
997
998
if removed {
999
report.updated.push ( RefUpdated {
1000
name: name.clone ( ) ,
1001
old_state: t.state,
1002
new_state: ObjectRef:: ZERO ,
1003
heads: vec! [ ] ,
1004
} ) ;
1005
}
1006
names.push ( name.clone ( ) ) ;
1007
results.push ( RefResult {
1008
name,
1009
ok: true ,
1010
reason: if removed {
1011
" withdrawn"
1012
} else {
1013
" already withdrawn"
1014
}
1015
.into ( ) ,
1016
} ) ;
1017
}
1018
Err ( e) => results.push ( RefResult {
1019
name,
1020
ok: false ,
1021
reason: e.reason,
1022
} ) ,
1023
}
1024
continue ;
1025
}
b2ef93bb Andy McCall 1 month ago ↶
1026
let new = ! view.tags.contains_key ( & t.name) ;
1ec6fdbc Andy McCall 16 days ago ↶
1027
match self .adopt_tag ( & mut view, t, policy.as_ref ( ) , & mut TagCheck:: Received) {
132b884b Andy McCall 1 month ago ↶
1028
Ok ( ( ) ) => {
b2ef93bb Andy McCall 1 month ago ↶
1029
1030
1031
1032
if new {
1033
report.updated.push ( RefUpdated {
1034
name: name.clone ( ) ,
1035
old_state: ObjectRef:: ZERO ,
1036
new_state: t.state,
1037
heads: t.heads.clone ( ) ,
1038
} ) ;
1039
}
132b884b Andy McCall 1 month ago ↶
1040
names.push ( name.clone ( ) ) ;
75167672 Andy McCall 1 month ago
1041
results.push ( RefResult {
1042
name,
1043
ok: true ,
1044
reason: String :: new( ) ,
1045
} ) ;
132b884b Andy McCall 1 month ago ↶
1046
}
75167672 Andy McCall 1 month ago
1047
Err ( e) => results.push ( RefResult {
1048
name,
1049
ok: false ,
1ec6fdbc Andy McCall 16 days ago ↶
1050
reason: e.reason,
75167672 Andy McCall 1 month ago
1051
} ) ,
132b884b Andy McCall 1 month ago ↶
1052
}
1053
}
98286406 Andy McCall 1 month ago ↶
1054
if ! names.is_empty ( ) {
75167672 Andy McCall 1 month ago
1055
self .record_op (
1056
& [ op_ref] ,
1057
& format! ( " push received: {} " , names.join ( " " ) ) ,
1058
view,
1059
) ? ;
98286406 Andy McCall 1 month ago ↶
1060
}
7aa2dc93 Andy McCall 1 month ago ↶
1061
Ok ( report)
98286406 Andy McCall 1 month ago ↶
1062
}
1063
be451356 Andy McCall 1 month ago ↶
1064
1065
1066
1067
1068
fn record_update_attest (
1069
& self ,
1070
u : & RefUpdate,
1071
sa : & SignedAttest,
1072
) -> std:: result:: Result< ( ) , String> {
1073
let name = & u.name;
1074
let last = self
1075
.latest_ref_attest ( name)
1076
.map_err ( | e | format! ( " reading the last attestation of {name:?} : {e} " ) ) ?
1077
.and_then ( | ( _, a ) | match a.attest.body {
1078
AttestBody:: Ref { serial, .. } => Some ( serial) ,
1079
_ => None ,
1080
} ) ;
1081
self .check_ref_attest ( sa, name, & u.old_state, & u.new_state, last, false ) ? ;
1082
let store = | e : & dyn std:: fmt:: Display| format! ( " storing the attestation of {name:?} : {e} " ) ;
1083
let r = self .store.put_attest ( & sa.attest) .map_err ( | e | store ( & e) ) ? ;
1084
for sig in & sa.sigs {
1085
self .store.put_signature ( & r, sig) .map_err ( | e | store ( & e) ) ? ;
f53cbe7a Andy McCall 18 days ago ↶
1086
}
1087
self .set_ref_attest ( name, & r) .map_err ( | e | store ( & e) ) ? ;
1088
1089
let certified = sa
1090
.sigs
1091
.first ( )
1092
.is_some_and ( | s | self .store.certificate_of ( & s.key) .ok ( ) .flatten ( ) .is_some ( ) ) ;
1093
if certified {
1094
self .record_acceptance ( & r) .map_err ( | e | store ( & e) ) ? ;
be451356 Andy McCall 1 month ago ↶
1095
}
f53cbe7a Andy McCall 18 days ago ↶
1096
Ok ( ( ) )
be451356 Andy McCall 1 month ago ↶
1097
}
1098
f53cbe7a Andy McCall 18 days ago ↶
1099
1100
1101
pub ( crate ) fn record_acceptance ( & self , r : & ObjectRef) -> Result< ( ) > {
1102
let Some ( acceptor) = & self .acceptor else {
1103
return Ok ( ( ) ) ;
1104
} ;
1105
let ( id, sk) = ( & acceptor.0 , & acceptor.1 ) ;
1106
let attest = Attest {
1107
repo: self .id ( ) ? ,
1108
hlc: Hlc:: now( ) ,
1109
body: AttestBody:: Accepted { attest: * r } ,
1110
} ;
1111
let sig = sk.sign ( Domain:: Attest, & id.hash ( ) , & attest.hash ( ) ) ;
1112
self .store.put_identity ( id) ? ;
1113
let a = self .store.put_attest ( & attest) ? ;
1114
self .store.put_signature ( & a, & sig) ? ;
1115
self .store.index_add_pub ( " accepted" , r, & a) ? ;
1116
Ok ( ( ) )
1117
}
1118
1119
1120
pub fn acceptance_of ( & self , r : & ObjectRef) -> Result< Option< SignedAttest> > {
1121
let Some ( a) = self .store.index_get_pub ( " accepted" , r) ? .into_iter ( ) .next ( ) else {
1122
return Ok ( None ) ;
1123
} ;
1124
Ok ( Some ( SignedAttest {
1125
attest: self .store.get_attest ( & a) ? ,
1126
sigs: self .store.signatures ( & a) ? ,
1127
} ) )
1128
}
1129
1130
1131
1132
1133
1134
pub ( crate ) fn certified_time (
1135
& self ,
1136
signer : & KeyId,
1137
sa : & SignedAttest,
1138
accepted : Option< & SignedAttest> ,
1139
) -> u64 {
1ec6fdbc Andy McCall 16 days ago ↶
1140
self .issuer_acceptance ( signer, sa, accepted)
1141
.unwrap_or ( sa.attest.hlc.wall_ms)
1142
}
1143
1144
1145
1146
pub ( crate ) fn issuer_acceptance (
1147
& self ,
1148
signer : & KeyId,
1149
sa : & SignedAttest,
1150
accepted : Option< & SignedAttest> ,
1151
) -> Option< u64 > {
1152
let acc = accepted? ;
1153
let c = self .store.certificate_of ( signer) .ok ( ) .flatten ( ) ? ;
1154
let cert = self .store.get_certificate ( & c) .ok ( ) ? ;
f53cbe7a Andy McCall 18 days ago ↶
1155
let AttestBody:: Accepted { attest } = & acc.attest.body else {
1ec6fdbc Andy McCall 16 days ago ↶
1156
return None ;
f53cbe7a Andy McCall 18 days ago ↶
1157
} ;
1ec6fdbc Andy McCall 16 days ago ↶
1158
let sig = acc.sigs.iter ( ) .find ( | s | s.key = = cert.cert.issuer ) ? ;
1159
let issuer = self .store.get_identity ( & cert.cert.issuer) .ok ( ) ? ;
1160
( * attest = = sa.attest.hash ( )
1161
& & verify_signature ( & issuer, sig, Domain:: Attest, & acc.attest.hash ( ) ) .is_ok ( ) )
1162
.then_some ( acc.attest.hlc.wall_ms)
1163
}
1164
1165
1166
1167
1168
pub ( crate ) fn keep_acceptance ( & self , r : & ObjectRef, acc : & SignedAttest) -> Result< ( ) > {
1169
let a = self .store.put_attest ( & acc.attest) ? ;
1170
for sig in & acc.sigs {
1171
self .store.put_signature ( & a, sig) ? ;
f53cbe7a Andy McCall 18 days ago ↶
1172
}
1ec6fdbc Andy McCall 16 days ago ↶
1173
self .store.index_add_pub ( " accepted" , r, & a) ? ;
1174
Ok ( ( ) )
f53cbe7a Andy McCall 18 days ago ↶
1175
}
1176
028545df Andy McCall 17 days ago ↶
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
# [ allow ( clippy::too_many_arguments ) ]
1187
pub ( crate ) fn authorize_in_time (
1188
& self ,
1189
p : & crate:: policy:: Policy,
1190
remote_name : & str ,
1191
r : & crate:: protocol:: RemoteRef,
1192
sa : & SignedAttest,
1193
signer : & KeyId,
1194
log : & super:: transparency:: LogCheck,
1195
notes : & mut Vec< String> ,
1196
) -> Result< ( ) > {
1197
use super :: transparency:: { gap_note, judge, Timed} ;
1198
let own = sa.attest.hlc.wall_ms;
1199
let at = self .certified_time ( signer, sa, r.accepted.as_ref ( ) ) ;
1200
let time = log.time_of ( & r.name) ;
1201
let check = | t_delegate : u64 , t_cert : u64 | {
1202
self .delegate_authorized ( p, signer, & r.name, t_delegate)
1203
| | self .certified_authorized ( p, signer, & r.name, Scope:: REFS , t_cert)
1204
} ;
1205
let before = if at ! = own {
1206
" the host's acceptance"
1207
} else {
1208
" the time it claims"
1209
} ;
1210
let what = format! ( " {remote_name} /{} " , r.name) ;
1211
match judge ( time.as_ref ( ) .ok ( ) .map ( | i | i.ms ( ) ) , | t | check ( t, t) , | | check ( own, at) ) {
1212
Timed:: Refused => {
1213
return fail ( format! (
1214
" {what} : attested by {} , which the policy does not authorize for this bookmark; a policy owner can grant it with `oxy policy grant`" ,
1215
signer.short ( 12 )
1216
) )
1217
}
1218
Timed:: Integrated => { }
1219
Timed:: Disagrees => notes.push ( format! (
1220
" {what} : {} 's authority had lapsed when witness {} first saw its attestation, though not at {before} ; accepted while transparency logs are new" ,
1221
signer.short ( 12 ) ,
1222
time.as_ref ( ) .map ( | i | i.witness.as_str ( ) ) .unwrap_or ( " ?" )
1223
) ) ,
1224
Timed:: Fallback if log.kept => notes.push ( format! (
1225
" {what} : {} checked at {before} , not at a witnessed time: {} " ,
1226
signer.short ( 12 ) ,
1227
time.as_ref ( ) .err ( ) .map ( String :: as_str) .unwrap_or ( " none" )
1228
) ) ,
1229
Timed:: Fallback => { }
1230
}
1231
if let Some ( n) = time.ok ( ) .and_then ( | i | gap_note ( own, i) ) {
1232
notes.push ( format! ( " {what} 's attestation {n} " ) ) ;
1233
}
1234
Ok ( ( ) )
1235
}
1236
f8c69576 Andy McCall 1 month ago ↶
1237
8c30d814 Andy McCall 1 month ago ↶
1238
1239
1240
1241
f8c69576 Andy McCall 1 month ago ↶
1242
1243
1244
fn apply_deletion (
1245
& self ,
1246
view : & mut View,
1247
u : & RefUpdate,
1248
policy : Option< & crate:: policy:: Policy> ,
1249
) -> std:: result:: Result< ( ) , String> {
1250
let Some ( current) = view.bookmarks.get ( & u.name) .copied ( ) else {
1251
return Err ( format! ( " no bookmark {:?} to delete" , u.name) ) ;
1252
} ;
1253
if current ! = u.old_state {
1254
return Err ( " stale: the remote bookmark has moved; pull first" .into ( ) ) ;
1255
}
8c30d814 Andy McCall 1 month ago ↶
1256
if ! self .is_bare ( ) & & u.name = = self .config.bookmark {
f8c69576 Andy McCall 1 month ago ↶
1257
return Err ( format! (
8c30d814 Andy McCall 1 month ago ↶
1258
" {:?} is this repository's default bookmark (checked out there) and cannot be deleted" ,
f8c69576 Andy McCall 1 month ago ↶
1259
u.name
1260
) ) ;
1261
}
1262
if let Some ( p) = policy {
1263
let Some ( sa) = & u.attestation else {
1264
return Err ( format! (
1265
" deleting {:?} requires a signed reference attestation under this repository's policy" ,
1266
u.name
1267
) ) ;
1268
} ;
1269
let signer = sa
1270
.sigs
1271
.first ( )
1272
.map ( | s | s.key )
1273
.ok_or ( " attestation carries no signature" ) ? ;
f0a517d2 Andy McCall 18 days ago ↶
1274
1275
let now = Hlc:: now( ) .wall_ms;
7ba155f2 Andy McCall 1 month ago ↶
1276
if ! p.authorizes ( & signer, & u.name)
1277
& & ! self .delegate_authorized ( p, & signer, & u.name, sa.attest.hlc.wall_ms)
f0a517d2 Andy McCall 18 days ago ↶
1278
& & ! self .certified_authorized ( p, & signer, & u.name, Scope:: REFS , now)
7ba155f2 Andy McCall 1 month ago ↶
1279
{
f8c69576 Andy McCall 1 month ago ↶
1280
return Err ( format! (
1281
" key {} may not delete {:?} under this repository's policy" ,
1282
signer.short ( 12 ) ,
1283
u.name
1284
) ) ;
1285
}
1286
}
1287
if let Some ( sa) = & u.attestation {
be451356 Andy McCall 1 month ago ↶
1288
self .record_update_attest ( u, sa) ? ;
f8c69576 Andy McCall 1 month ago ↶
1289
}
1290
view.bookmarks.remove ( & u.name) ;
1291
Ok ( ( ) )
1292
}
1293
75167672 Andy McCall 1 month ago
1294
fn apply_update (
1295
& self ,
1296
view : & mut View,
1297
u : & RefUpdate,
1298
policy : Option< & crate:: policy:: Policy> ,
1299
) -> std:: result:: Result< ( ) , String> {
83e0677b Andy McCall 1 month ago ↶
1300
if u.name = = " policy" {
75167672 Andy McCall 1 month ago
1301
return Err (
1302
" the policy reference is updated by sending a policy, not a bookmark update" .into ( ) ,
1303
) ;
83e0677b Andy McCall 1 month ago ↶
1304
}
75167672 Andy McCall 1 month ago
1305
let empty = self
1306
.store
1307
.put_state ( & StateObject:: new( vec! [ ] ) )
1308
.map_err ( | e | e.to_string ( ) ) ? ;
f8c69576 Andy McCall 1 month ago ↶
1309
if u.new_state.is_zero ( ) {
1310
return self .apply_deletion ( view, u, policy) ;
1311
}
98286406 Andy McCall 1 month ago ↶
1312
let current = view.bookmarks.get ( & u.name) .copied ( ) .unwrap_or ( empty) ;
1313
if current ! = u.old_state {
1314
return Err ( " stale: the remote bookmark has moved; pull first" .into ( ) ) ;
1315
}
75167672 Andy McCall 1 month ago
1316
let new_state = self
1317
.store
1318
.get_state ( & u.new_state)
1319
.map_err ( | _| " new state object is missing" .to_string ( ) ) ? ;
98286406 Andy McCall 1 month ago ↶
1320
for h in & new_state.heads {
1321
if ! self .store.has ( h) {
1322
return Err ( format! ( " head {} is missing" , h.short ( 12 ) ) ) ;
1323
}
1324
}
1325
if ! u.force {
75167672 Andy McCall 1 month ago
1326
let old_heads = self
1327
.store
1328
.get_state ( & current)
1329
.map_err ( | e | e.to_string ( ) ) ?
1330
.heads;
1331
let closure = self
1332
.closure_in_store ( & new_state.heads)
1333
.map_err ( | e | e.to_string ( ) ) ? ;
98286406 Andy McCall 1 month ago ↶
1334
if let Some ( h) = old_heads.iter ( ) .find ( | h | ! closure.contains ( h) ) {
75167672 Andy McCall 1 month ago
1335
return Err ( format! (
1336
" not a fast-forward: current head {} would be dropped (use --force)" ,
1337
h.short ( 12 )
1338
) ) ;
98286406 Andy McCall 1 month ago ↶
1339
}
1340
}
83e0677b Andy McCall 1 month ago ↶
1341
if let Some ( p) = policy {
1342
let Some ( sa) = & u.attestation else {
75167672 Andy McCall 1 month ago
1343
return Err ( format! (
1344
" {:?} requires a signed reference attestation under this repository's policy" ,
1345
u.name
1346
) ) ;
83e0677b Andy McCall 1 month ago ↶
1347
} ;
75167672 Andy McCall 1 month ago
1348
let signer = sa
1349
.sigs
1350
.first ( )
1351
.map ( | s | s.key )
1352
.ok_or ( " attestation carries no signature" ) ? ;
f0a517d2 Andy McCall 18 days ago ↶
1353
1354
let now = Hlc:: now( ) .wall_ms;
7ba155f2 Andy McCall 1 month ago ↶
1355
if ! p.authorizes ( & signer, & u.name)
1356
& & ! self .delegate_authorized ( p, & signer, & u.name, sa.attest.hlc.wall_ms)
f0a517d2 Andy McCall 18 days ago ↶
1357
& & ! self .certified_authorized ( p, & signer, & u.name, Scope:: REFS , now)
7ba155f2 Andy McCall 1 month ago ↶
1358
{
75167672 Andy McCall 1 month ago
1359
return Err ( format! (
1360
" key {} may not update {:?} under this repository's policy" ,
1361
signer.short ( 12 ) ,
1362
u.name
1363
) ) ;
83e0677b Andy McCall 1 month ago ↶
1364
}
75167672 Andy McCall 1 month ago
1365
let old_heads = self
1366
.store
1367
.get_state ( & current)
1368
.map_err ( | e | e.to_string ( ) ) ?
1369
.heads;
83e0677b Andy McCall 1 month ago ↶
1370
self .state_allowed ( & old_heads, & new_state.heads, p, & u.name) ? ;
1371
}
98286406 Andy McCall 1 month ago ↶
1372
if let Some ( sa) = & u.attestation {
be451356 Andy McCall 1 month ago ↶
1373
self .record_update_attest ( u, sa) ? ;
98286406 Andy McCall 1 month ago ↶
1374
}
1375
view.bookmarks.insert ( u.name.clone ( ) , u.new_state) ;
1376
Ok ( ( ) )
1377
}
1378
1379
1380
1381
fn remote_url ( & self , name : & str ) -> Result< String> {
75167672 Andy McCall 1 month ago
1382
self .config.remotes.get ( name) .cloned ( ) .ok_or_else ( | | {
42ccf504 Andy McCall 27 days ago ↶
1383
let names: Vec< & str > = self .config.remotes.keys ( ) .map ( String :: as_str) .collect ( ) ;
1384
RepoError:: Msg( match names.as_slice ( ) {
1385
[ ] => format! ( " no remote named {name:?} ; add one with `oxy remote add`" ) ,
1386
_ if name = = " origin" & & names.len ( ) > 1 & & self .config.default_remote.is_none ( ) => format! (
1387
" this repository has no remote named origin, and several others ({} ): name one (`oxy pull {} `), or make one the default with `oxy config core.remote {} `" ,
1388
names.join ( " , " ) ,
1389
names[ 0 ] ,
1390
names[ 0 ]
1391
) ,
1392
_ => format! (
1393
" no remote named {name:?} ; this repository has {} " ,
1394
names.join ( " , " )
1395
) ,
1396
} )
75167672 Andy McCall 1 month ago
1397
} )
98286406 Andy McCall 1 month ago ↶
1398
}
1399
75167672 Andy McCall 1 month ago
1400
1401
1402
05e71ed6 Andy McCall 1 month ago ↶
1403
fn check_remote_id (
1404
& self ,
1405
remote : & dyn crate:: protocol:: Remote,
1406
remote_name : & str ,
1407
allow_unbound : bool ,
1408
) -> Result< ( ) > {
75167672 Andy McCall 1 month ago
1409
let theirs = remote.repo_id ( ) ? ;
1410
if theirs = = self .id ( ) ? {
1411
return Ok ( ( ) ) ;
1412
}
1413
if theirs = = crate :: protocol:: UNBOUND_ID {
1414
if allow_unbound {
1415
return Ok ( ( ) ) ;
1416
}
05e71ed6 Andy McCall 1 month ago ↶
1417
return fail ( format! (
1418
" remote {remote_name:?} is empty and unbound: push to it first"
1419
) ) ;
75167672 Andy McCall 1 month ago
1420
}
05e71ed6 Andy McCall 1 month ago ↶
1421
fail ( format! (
3e5772cc Andy McCall 1 month ago ↶
1422
" remote {remote_name:?} is a different repository (repository IDs differ); check its URL with `oxy remote list`"
05e71ed6 Andy McCall 1 month ago ↶
1423
) )
75167672 Andy McCall 1 month ago
1424
}
1425
ff1f62fe Andy McCall 1 month ago ↶
1426
1427
1428
3e5772cc Andy McCall 1 month ago ↶
1429
pub ( crate ) fn remote_options ( & self , name : & str ) -> RemoteOptions {
ff1f62fe Andy McCall 1 month ago ↶
1430
let url = self .config.remotes.get ( name) .cloned ( ) .unwrap_or_default ( ) ;
1431
let mut options = RemoteOptions {
75167672 Andy McCall 1 month ago
1432
repo_id: self .id ( ) .ok ( ) ,
ff1f62fe Andy McCall 1 month ago ↶
1433
token: self .config.remote_tokens.get ( name) .cloned ( ) ,
1434
ca: self .config.remote_cas.get ( name) .map ( PathBuf:: from) ,
9f9e72b9 Andy McCall 1 month ago ↶
1435
cache_dir: Some ( self .oxy.join ( " remotes" ) .join ( name) .join ( " strata" ) ) ,
68a92484 Andy McCall 22 days ago ↶
1436
.. RemoteOptions:: default( )
ff1f62fe Andy McCall 1 month ago ↶
1437
} ;
1438
self .fill_credentials ( & url, & mut options) ;
1439
options
1440
}
1441
1442
1443
1444
pub fn credentials ( & self ) -> crate:: credentials:: Credentials {
1445
crate :: credentials:: Credentials:: at(
1446
self .user_config
1447
.parent ( )
1448
.map ( Path:: to_path_buf)
1449
.unwrap_or_else ( default_home) ,
1450
)
1451
}
1452
1453
1454
1455
68a92484 Andy McCall 22 days ago ↶
1456
1457
1458
1459
ff1f62fe Andy McCall 1 month ago ↶
1460
fn fill_credentials ( & self , url : & str , options : & mut RemoteOptions) {
1461
if options.token.is_some ( ) & & options.ca.is_some ( ) {
1462
return ;
1463
}
68a92484 Andy McCall 22 days ago ↶
1464
let explicit =
1465
options.token.is_some ( ) | | std:: env:: var( " OXY_TOKEN" ) .is_ok_and ( | t | ! t.is_empty ( ) ) ;
ff1f62fe Andy McCall 1 month ago ↶
1466
let stored = self .credentials ( ) .options_for ( url) ;
1467
options.token = options.token.take ( ) .or ( stored.token) ;
1468
options.ca = options.ca.take ( ) .or ( stored.ca) ;
68a92484 Andy McCall 22 days ago ↶
1469
let enclosing = self .enclosing_credentials ( url) ;
1470
if options.token.is_none ( ) {
1471
options.token = enclosing.iter ( ) .find_map ( | ( t , _) | t.clone ( ) ) ;
1472
}
1473
if options.ca.is_none ( ) {
1474
options.ca = enclosing.iter ( ) .find_map ( | ( _, c ) | c.clone ( ) ) ;
1475
}
1476
if ! explicit {
1477
for t in enclosing.into_iter ( ) .filter_map ( | ( t , _) | t ) {
1478
if options.token.as_ref ( ) ! = Some ( & t) & & ! options.fallback_tokens.contains ( & t) {
1479
options.fallback_tokens.push ( t) ;
1480
}
1481
}
2b5ee371 Andy McCall 1 month ago ↶
1482
}
68a92484 Andy McCall 22 days ago ↶
1483
}
1484
1485
1486
1487
fn enclosing_credentials ( & self , url : & str ) -> Vec< ( Option< String> , Option< PathBuf> ) > {
1488
let mut out = Vec :: new( ) ;
ff1f62fe Andy McCall 1 month ago ↶
1489
let Some ( hub) = crate :: credentials:: hub_of( url) else {
68a92484 Andy McCall 22 days ago ↶
1490
return out;
ff1f62fe Andy McCall 1 month ago ↶
1491
} ;
1492
let mut at = self .root.parent ( ) ;
1493
while let Some ( dir) = at {
1494
let Ok ( cfg) = read_config_file ( & dir.join ( OXY_DIR ) .join ( " config" ) ) else {
1495
break ;
1496
} ;
1497
for ( key, remote_url) in & cfg {
1498
let Some ( name) = key
1499
.strip_prefix ( " remote." )
1500
.and_then ( | k | k.strip_suffix ( " .url" ) )
1501
else {
1502
continue ;
1503
} ;
1504
if crate :: credentials:: hub_of( remote_url) .as_deref ( ) ! = Some ( hub.as_str ( ) ) {
1505
continue ;
1506
}
68a92484 Andy McCall 22 days ago ↶
1507
out.push ( (
1508
cfg.get ( & format! ( " remote.{name} .token" ) ) .cloned ( ) ,
1509
cfg.get ( & format! ( " remote.{name} .ca" ) ) .map ( PathBuf:: from) ,
1510
) ) ;
ff1f62fe Andy McCall 1 month ago ↶
1511
}
1512
at = dir.parent ( ) ;
1513
}
68a92484 Andy McCall 22 days ago ↶
1514
out
98286406 Andy McCall 1 month ago ↶
1515
}
1516
d82e4409 Andy McCall 1 month ago ↶
1517
1518
1519
pub fn push_seals ( & self , remote_name : & str , seals : & [ObjectRef]) -> Result< ( ) > {
1520
let remote = self .open_named_remote ( remote_name) ? ;
1521
self .check_remote_id ( remote.as_ref ( ) , remote_name, false ) ? ;
1522
let mut bundle = Bundle:: default( ) ;
1523
for r in seals {
1524
let attest = self .store.get_attest ( r) ? ;
1525
let sigs = self .store.signatures ( r) ? ;
4213c41d Andy McCall 1 month ago ↶
1526
bundle
1527
.attests
1528
.push ( crate :: protocol:: SignedAttest { attest, sigs } ) ;
d82e4409 Andy McCall 1 month ago ↶
1529
}
1530
let results = remote.push ( bundle, vec! [ ] , None , vec! [ ] ) ? ;
1531
if let Some ( r) = results.iter ( ) .find ( | r | ! r.ok) {
1532
return fail ( format! ( " {} : {} " , r.name, r.reason) ) ;
1533
}
1534
Ok ( ( ) )
1535
}
1536
1537
1538
pub fn remote_for_url ( & self , base : & str ) -> Option< String> {
1539
let base = base.trim_end_matches ( ' /' ) ;
4213c41d Andy McCall 1 month ago ↶
1540
self .config
1541
.remotes
1542
.iter ( )
1543
.find ( | ( _, url ) | url.trim_end_matches ( ' /' ) = = base )
1544
.map ( | ( name , _) | name.clone ( ) )
d82e4409 Andy McCall 1 month ago ↶
1545
}
1546
1547
ff1f62fe Andy McCall 1 month ago ↶
1548
d82e4409 Andy McCall 1 month ago ↶
1549
pub fn open_remote_at ( & self , url : & str ) -> Result< ( String, Box< dyn crate:: protocol:: Remote> ) > {
1550
if let Some ( name) = self .remote_for_url ( url) {
1551
return Ok ( ( name.clone ( ) , self .open_named_remote ( & name) ? ) ) ;
1552
}
1553
let options = RemoteOptions {
1554
repo_id: self .id ( ) .ok ( ) ,
ff1f62fe Andy McCall 1 month ago ↶
1555
.. self .credentials_for ( url)
d82e4409 Andy McCall 1 month ago ↶
1556
} ;
1557
Ok ( ( url.to_string ( ) , open_remote ( url, & options) ? ) )
1558
}
1559
1560
1561
1562
pub fn options_for_url ( & self , url : & str ) -> RemoteOptions {
1563
match self .remote_for_url ( url) {
1564
Some ( name) => self .remote_options ( & name) ,
1565
None => RemoteOptions {
1566
repo_id: self .id ( ) .ok ( ) ,
ff1f62fe Andy McCall 1 month ago ↶
1567
.. self .credentials_for ( url)
d82e4409 Andy McCall 1 month ago ↶
1568
} ,
1569
}
1570
}
1571
c8d9059e Andy McCall 10 days ago ↶
1572
pub ( crate ) fn open_named_remote ( & self , name : & str ) -> Result< Box< dyn crate:: protocol:: Remote> > {
2b5ee371 Andy McCall 1 month ago ↶
1573
open_remote ( & self .remote_url ( name) ? , & self .remote_options ( name) )
98286406 Andy McCall 1 month ago ↶
1574
}
1575
1576
fn serial_path ( & self , remote : & str , bookmark : & str ) -> PathBuf {
75167672 Andy McCall 1 month ago
1577
self .oxy
1578
.join ( " remotes" )
1579
.join ( remote)
1580
.join ( format! ( " {bookmark} .serial" ) )
98286406 Andy McCall 1 month ago ↶
1581
}
1582
1583
fn last_seen_serial ( & self , remote : & str , bookmark : & str ) -> Option< u64 > {
75167672 Andy McCall 1 month ago
1584
fs:: read_to_string( self .serial_path ( remote, bookmark) )
1585
.ok ( )
1586
.and_then ( | s | s.trim ( ) .parse ( ) .ok ( ) )
98286406 Andy McCall 1 month ago ↶
1587
}
1588
1589
fn record_serial ( & self , remote : & str , bookmark : & str , serial : u64 ) -> Result< ( ) > {
1590
let p = self .serial_path ( remote, bookmark) ;
1591
fs:: create_dir_all( p.parent ( ) .unwrap ( ) ) ? ;
1592
write_atomic ( & p, serial.to_string ( ) .as_bytes ( ) )
1593
}
1594
83e0677b Andy McCall 1 month ago ↶
1595
fn policy_serial_path ( & self , remote : & str ) -> PathBuf {
1596
self .oxy.join ( " remotes" ) .join ( remote) .join ( " policy.serial" )
1597
}
1598
1599
1600
fn remote_policy_serial ( & self , remote : & str ) -> Option< u64 > {
75167672 Andy McCall 1 month ago
1601
fs:: read_to_string( self .policy_serial_path ( remote) )
1602
.ok ( )
1603
.and_then ( | s | s.trim ( ) .parse ( ) .ok ( ) )
83e0677b Andy McCall 1 month ago ↶
1604
}
1605
1606
fn record_policy_serial ( & self , remote : & str , serial : u64 ) -> Result< ( ) > {
1607
let p = self .policy_serial_path ( remote) ;
1608
fs:: create_dir_all( p.parent ( ) .unwrap ( ) ) ? ;
1609
write_atomic ( & p, serial.to_string ( ) .as_bytes ( ) )
1610
}
1611
b3c5a59a Andy McCall 1 month ago ↶
1612
fn lazy_dir ( & self ) -> PathBuf {
1613
self .oxy.join ( " lazy" )
1614
}
1615
1616
1617
fn register_lazy ( & self , blob : & ObjectRef, remote : & str ) -> Result< ( ) > {
1618
fs:: create_dir_all( self .lazy_dir ( ) ) ? ;
1619
write_atomic ( & self .lazy_dir ( ) .join ( blob.to_hex ( ) ) , remote.as_bytes ( ) )
1620
}
1621
1622
1623
pub fn lazy_remote ( & self , blob : & ObjectRef) -> Option< String> {
75167672 Andy McCall 1 month ago
1624
fs:: read_to_string( self .lazy_dir ( ) .join ( blob.to_hex ( ) ) )
1625
.ok ( )
1626
.map ( | s | s.trim ( ) .to_string ( ) )
b3c5a59a Andy McCall 1 month ago ↶
1627
}
1628
1629
1630
pub ( crate ) fn fetch_lazy_blob ( & self , blob : & ObjectRef) -> Result< ( ) > {
1631
let Some ( remote_name) = self .lazy_remote ( blob) else {
1632
return Err ( RepoError:: Store( StoreError:: NotFound( * blob) ) ) ;
1633
} ;
1634
let remote = self .open_named_remote ( & remote_name) ? ;
1635
let objects = remote.objects ( & [ * blob] ) ? ;
1636
for ( ty, body) in objects {
1637
if matches! ( ty, ObjectType:: Blob | ObjectType:: Chunk) {
1638
self .store.put ( ty, & body) ? ;
1639
}
1640
}
1641
if ! self .store.has ( blob) {
75167672 Andy McCall 1 month ago
1642
return fail ( format! (
1643
" {remote_name} did not send blob {} " ,
1644
blob.short ( 12 )
1645
) ) ;
b3c5a59a Andy McCall 1 month ago ↶
1646
}
1647
let _ = fs:: remove_file( self .lazy_dir ( ) .join ( blob.to_hex ( ) ) ) ;
1648
Ok ( ( ) )
1649
}
1650
1651
1652
1653
fn register_missing_blobs ( & self , changes : & [ChangeHash], remote : & str ) -> Result< usize > {
1654
let mut n = 0 ;
1655
for h in changes {
1656
let c = self .store.get_change ( h) ? ;
1657
for e in & c.edits {
1658
if let Edit:: Replace { old, new, .. } = e {
1659
for b in [ old, new] .into_iter ( ) .flatten ( ) {
1660
if ! self .store.has ( b) {
1661
self .register_lazy ( b, remote) ? ;
1662
n + = 1 ;
1663
}
1664
}
1665
}
1666
}
1667
}
1668
Ok ( n)
1669
}
1670
98286406 Andy McCall 1 month ago ↶
1671
d82e4409 Andy McCall 1 month ago ↶
1672
pub fn known_heads ( & self , view : & View) -> Result< Vec< ChangeHash> > {
98286406 Andy McCall 1 month ago ↶
1673
let mut have: BTreeSet< ChangeHash> = BTreeSet:: new( ) ;
75167672 Andy McCall 1 month ago
1674
for st in view
1675
.bookmarks
1676
.values ( )
1677
.chain ( view.remotes.values ( ) .flat_map ( | b | b.values ( ) ) )
1678
{
98286406 Andy McCall 1 month ago ↶
1679
if let Ok ( s) = self .store.get_state ( st) {
1680
have.extend ( s.heads) ;
1681
}
1682
}
1683
have.extend ( view.workspaces.values ( ) .copied ( ) ) ;
1684
Ok ( have.into_iter ( ) .collect ( ) )
1685
}
1686
1687
83e0677b Andy McCall 1 month ago ↶
1688
pub fn fetch ( & self , remote_name : & str ) -> Result< FetchReport> {
98286406 Andy McCall 1 month ago ↶
1689
let remote = self .open_named_remote ( remote_name) ? ;
75167672 Andy McCall 1 month ago
1690
self .check_remote_id ( remote.as_ref ( ) , remote_name, false ) ? ;
83e0677b Andy McCall 1 month ago ↶
1691
let resp = remote.refs ( ) ? ;
4b9d0677 Andy McCall 18 days ago ↶
1692
028545df Andy McCall 17 days ago ↶
1693
let log = self .check_log (
4b9d0677 Andy McCall 18 days ago ↶
1694
& self .remote_url ( remote_name) ? ,
1695
self .config.remote_cas.get ( remote_name) .map ( Path:: new) ,
1696
& resp,
1697
) ? ;
028545df Andy McCall 17 days ago ↶
1698
let mut log_notes = log.notes.clone ( ) ;
83e0677b Andy McCall 1 month ago ↶
1699
1700
1701
1702
1703
1704
let local_policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp.policy ) ;
1705
let seen = self .remote_policy_serial ( remote_name) ;
1706
let mut unverified = false ;
1707
match & resp.policy {
1708
Some ( sp) => {
1709
if seen.is_some_and ( | s | sp.policy.serial < s ) {
1710
return fail ( format! ( " {remote_name} presents policy serial {} but presented {} before: refusing the downgrade" , sp.policy.serial, seen.unwrap ( ) ) ) ;
1711
}
1712
match & local_policy {
1713
Some ( l) if sp.policy.serial < l.serial => { }
1714
Some ( l) if sp.policy.serial = = l.serial => {
1715
if sp.policy.hash ( ) ! = l.hash ( ) {
75167672 Andy McCall 1 month ago
1716
return fail ( format! (
1717
" {remote_name} presents a different policy with the same serial {} " ,
1718
l.serial
1719
) ) ;
83e0677b Andy McCall 1 month ago ↶
1720
}
1721
}
28fc23d7 Andy McCall 1 month ago ↶
1722
_ => {
75167672 Andy McCall 1 month ago
1723
self .adopt_policy_chain (
1724
& resp.history,
1725
sp,
1726
& format! ( " oxy fetch {remote_name} " ) ,
1727
)
1728
.map_err ( | e | RepoError:: Msg( format! ( " policy from {remote_name} : {e} " ) ) ) ? ;
83e0677b Andy McCall 1 month ago ↶
1729
}
1730
}
1731
self .record_policy_serial ( remote_name, sp.policy.serial) ? ;
1732
}
1733
None => {
1734
if seen.is_some ( ) {
1735
return fail ( format! ( " {remote_name} presented a policy before but has none now: refusing the downgrade" ) ) ;
1736
}
1737
unverified = true ;
1738
}
1739
}
75167672 Andy McCall 1 month ago
1740
let policy = if unverified {
1741
None
1742
} else {
1743
self .current_policy ( ) ? .map ( | ( _, sp ) | sp.policy )
1744
} ;
98286406 Andy McCall 1 month ago ↶
1745
let ( op_ref, op) = self .head_op ( ) ? ;
1746
let mut view = op.view.clone ( ) ;
1747
let have = self .known_heads ( & view) ? ;
1748
let mut report = Vec :: new( ) ;
d36ba2f7 Andy McCall 16 days ago ↶
1749
let mut skipped = Vec :: new( ) ;
b3c5a59a Andy McCall 1 month ago ↶
1750
let max_blob = self .config.max_blob;
83e0677b Andy McCall 1 month ago ↶
1751
for r in resp.refs {
091fef80 Andy McCall 1 month ago ↶
1752
let needed = {
1753
let _t = crate :: timing:: phase( " fetch: negotiate" ) ;
1754
remote.negotiate ( & have, & r.heads) ?
1755
} ;
1756
let bundle = {
1757
let _t = crate :: timing:: phase( " fetch: bundle" ) ;
1758
remote.fetch ( & needed, max_blob) ?
1759
} ;
83e0677b Andy McCall 1 month ago ↶
1760
1761
1762
f3811eb2 Andy McCall 11 days ago ↶
1763
1764
1765
let shallow = self .is_shallow ( ) ;
091fef80 Andy McCall 1 month ago ↶
1766
let imported = {
1767
let _t = crate :: timing:: phase( " fetch: import" ) ;
f3811eb2 Andy McCall 11 days ago ↶
1768
if shallow {
1769
self .import_bundle_shallow ( & bundle, false ) ?
1770
} else {
1771
self .import_bundle ( & bundle, false ) ?
1772
}
091fef80 Andy McCall 1 month ago ↶
1773
} ;
f3811eb2 Andy McCall 11 days ago ↶
1774
if shallow {
1775
self .refresh_boundary ( & imported) ? ;
1776
}
b3c5a59a Andy McCall 1 month ago ↶
1777
if max_blob.is_some ( ) {
1778
self .register_missing_blobs ( & imported, remote_name) ? ;
1779
}
f3811eb2 Andy McCall 11 days ago ↶
1780
let boundary = if shallow {
1781
self .boundary ( )
1782
} else {
1783
BTreeSet:: new( )
1784
} ;
98286406 Andy McCall 1 month ago ↶
1785
for h in & r.heads {
f3811eb2 Andy McCall 11 days ago ↶
1786
if ! self .store.has ( h) & & ! boundary.contains ( h) {
98286406 Andy McCall 1 month ago ↶
1787
return fail ( format! ( " remote did not send head {} " , h.short ( 12 ) ) ) ;
1788
}
1789
}
1790
let state = self .store.put_state ( & StateObject:: new( r.heads.clone ( ) ) ) ? ;
1791
if state ! = r.state {
75167672 Andy McCall 1 month ago
1792
return fail ( format! (
1793
" remote state {} does not match its heads" ,
1794
r.state.short ( 12 )
1795
) ) ;
98286406 Andy McCall 1 month ago ↶
1796
}
83e0677b Andy McCall 1 month ago ↶
1797
if let Some ( p) = & policy {
1798
let Some ( sa) = & r.attestation else {
75167672 Andy McCall 1 month ago
1799
return fail ( format! (
1800
" {remote_name} /{} has no attestation, which its policy requires" ,
1801
r.name
1802
) ) ;
83e0677b Andy McCall 1 month ago ↶
1803
} ;
75167672 Andy McCall 1 month ago
1804
let signer = sa
1805
.sigs
1806
.first ( )
1807
.map ( | s | s.key )
1808
.ok_or_else ( | | RepoError:: Msg( " attestation carries no signature" .into ( ) ) ) ? ;
028545df Andy McCall 17 days ago ↶
1809
if ! p.authorizes ( & signer, & r.name) {
1810
self .authorize_in_time ( p, remote_name, & r, sa, & signer, & log, & mut log_notes) ? ;
83e0677b Andy McCall 1 month ago ↶
1811
}
1812
}
98286406 Andy McCall 1 month ago ↶
1813
if let Some ( sa) = & r.attestation {
75167672 Andy McCall 1 month ago
1814
let AttestBody:: Ref {
1815
old_state,
1816
new_state,
1817
..
1818
} = & sa.attest.body
1819
else {
98286406 Andy McCall 1 month ago ↶
1820
return fail ( " remote sent a non-ref attestation for a bookmark" ) ;
1821
} ;
1822
let ( old_state, new_state) = ( * old_state, * new_state) ;
1823
let serial = self
d36ba2f7 Andy McCall 16 days ago ↶
1824
.check_ref_attest_body (
75167672 Andy McCall 1 month ago
1825
sa,
1826
& r.name,
1827
& old_state,
1828
& new_state,
1829
self .last_seen_serial ( remote_name, & r.name) ,
1830
true ,
1831
)
1832
.map_err ( | e | {
1833
RepoError:: Msg( format! ( " attestation for {} /{} : {e} " , remote_name, r.name) )
1834
} ) ? ;
98286406 Andy McCall 1 month ago ↶
1835
if new_state ! = r.state {
75167672 Andy McCall 1 month ago
1836
return fail ( format! (
1837
" attestation for {} /{} does not cover its current state" ,
1838
remote_name, r.name
1839
) ) ;
98286406 Andy McCall 1 month ago ↶
1840
}
d36ba2f7 Andy McCall 16 days ago ↶
1841
1842
1843
1844
1845
1846
1847
if let Err ( e) = self .verify_attest_signature ( sa) {
1848
let why = format! ( " attestation for {remote_name} /{} : {e} " , r.name) ;
1849
if r.name = = self .config.bookmark {
1850
return fail ( why) ;
1851
}
1852
skipped.push ( ( r.name, why) ) ;
1853
continue ;
1854
}
98286406 Andy McCall 1 month ago ↶
1855
let ar = self .store.put_attest ( & sa.attest) ? ;
1856
for sig in & sa.sigs {
1857
self .store.put_signature ( & ar, sig) ? ;
1858
}
1859
self .record_serial ( remote_name, & r.name, serial) ? ;
1860
}
75167672 Andy McCall 1 month ago
1861
view.remotes
1862
.entry ( remote_name.to_string ( ) )
1863
.or_default ( )
1864
.insert ( r.name.clone ( ) , state) ;
98286406 Andy McCall 1 month ago ↶
1865
report.push ( ( r.name, r.heads, imported.len ( ) ) ) ;
1866
}
132b884b Andy McCall 1 month ago ↶
1867
let mut new_tags = 0 ;
1868
for t in & resp.tags {
1869
if view.tags.contains_key ( & t.name) {
b63fc7a7 Andy McCall 11 days ago ↶
1870
continue ;
1871
}
1872
1873
if self .tag_withdrawal ( & t.name) ? .is_some ( ) {
132b884b Andy McCall 1 month ago ↶
1874
continue ;
1875
}
1876
75167672 Andy McCall 1 month ago
1877
let missing: Vec< ChangeHash> = t
1878
.heads
1879
.iter ( )
1880
.filter ( | h | ! self .store.has ( h) )
1881
.copied ( )
1882
.collect ( ) ;
132b884b Andy McCall 1 month ago ↶
1883
if ! missing.is_empty ( ) {
1884
let needed = remote.negotiate ( & self .known_heads ( & view) ? , & missing) ? ;
1885
let bundle = remote.fetch ( & needed, max_blob) ? ;
1886
self .import_bundle ( & bundle, false ) ? ;
1887
}
1888
self .store.put_state ( & StateObject:: new( t.heads.clone ( ) ) ) ? ;
1ec6fdbc Andy McCall 16 days ago ↶
1889
let mut check = TagCheck:: Fetched {
1890
remote: remote_name,
1891
log: & log,
1892
notes: & mut log_notes,
1893
} ;
1894
match self .adopt_tag ( & mut view, t, policy.as_ref ( ) , & mut check) {
1895
Ok ( ( ) ) => new_tags + = 1 ,
1896
1897
1898
Err ( e) if e.untimed => {
1899
skipped.push ( ( format! ( " tags/{} " , t.name) , e.reason) ) ;
1900
}
1901
Err ( e) => return fail ( format! ( " {remote_name} {} : {} " , t.name, e.reason) ) ,
1902
}
132b884b Andy McCall 1 month ago ↶
1903
}
b63fc7a7 Andy McCall 11 days ago ↶
1904
1905
1906
1907
let mut withdrawn_tags = Vec :: new( ) ;
1908
for t in & resp.withdrawn {
1909
if ! view.tags.contains_key ( & t.name) {
1910
continue ;
1911
}
1912
let mut check = TagCheck:: Fetched {
1913
remote: remote_name,
1914
log: & log,
1915
notes: & mut log_notes,
1916
} ;
1917
match self .adopt_withdrawal ( & mut view, t, policy.as_ref ( ) , & mut check) {
1918
Ok ( true ) => withdrawn_tags.push ( t.name.clone ( ) ) ,
1919
Ok ( false ) => { }
1920
Err ( e) => skipped.push ( (
1921
format! ( " tags/{} " , t.name) ,
1922
format! ( " withdrawn on {remote_name} , kept here: {} " , e.reason) ,
1923
) ) ,
1924
}
1925
}
98286406 Andy McCall 1 month ago ↶
1926
if view ! = op.view {
1927
self .record_op ( & [ op_ref] , & format! ( " oxy fetch {remote_name} " ) , view) ? ;
1928
}
6d3eefbc Andy McCall 1 month ago ↶
1929
let _ = self .run_hook (
1930
" post-fetch" ,
1931
& format! (
1932
" {{ \" event\" :\" post-fetch\" ,\" remote\" :{} ,\" bookmarks\" :{} }} " ,
1933
json_str ( remote_name) ,
75167672 Andy McCall 1 month ago
1934
json_array ( report.iter ( ) .map ( | ( n , heads , _) | format! (
1935
" {{ \" name\" :{} ,\" heads\" :{} }} " ,
1936
json_str ( n) ,
1937
json_array ( heads.iter ( ) .map ( | h | json_str ( & h.to_hex ( ) ) ) )
1938
) ) )
6d3eefbc Andy McCall 1 month ago ↶
1939
) ,
1940
) ;
75167672 Andy McCall 1 month ago
1941
Ok ( FetchReport {
1942
refs: report,
1943
unverified,
1944
new_tags,
b63fc7a7 Andy McCall 11 days ago ↶
1945
withdrawn_tags,
4b9d0677 Andy McCall 18 days ago ↶
1946
log_notes,
d36ba2f7 Andy McCall 16 days ago ↶
1947
skipped,
75167672 Andy McCall 1 month ago
1948
} )
98286406 Andy McCall 1 month ago ↶
1949
}
1950
2863456a Andy McCall 1 month ago ↶
1951
1952
1953
pub fn fetch_shallow ( & self , remote_name : & str , depth : u32 ) -> Result< usize > {
1954
let remote = self .open_named_remote ( remote_name) ? ;
75167672 Andy McCall 1 month ago
1955
self .check_remote_id ( remote.as_ref ( ) , remote_name, false ) ? ;
2863456a Andy McCall 1 month ago ↶
1956
let resp = remote.refs ( ) ? ;
1957
let bookmark = self .config.bookmark.clone ( ) ;
1958
if let Some ( sp) = & resp.policy {
75167672 Andy McCall 1 month ago
1959
self .adopt_policy_chain ( & resp.history, sp, " oxy clone --depth" )
1960
.map_err ( | e | RepoError:: Msg( format! ( " policy from {remote_name} : {e} " ) ) ) ? ;
2863456a Andy McCall 1 month ago ↶
1961
self .record_policy_serial ( remote_name, sp.policy.serial) ? ;
1962
}
1963
let Some ( r) = resp.refs.into_iter ( ) .find ( | r | r.name = = bookmark ) else {
1964
return fail ( format! ( " {remote_name} has no bookmark {bookmark:?} " ) ) ;
1965
} ;
1966
if r.heads.is_empty ( ) {
1967
return Ok ( 0 ) ;
1968
}
1969
f3811eb2 Andy McCall 11 days ago ↶
1970
let cp_bundle = {
1971
let _t = crate :: timing:: phase( " shallow: checkpoint request" ) ;
1972
remote.checkpoint ( & r.heads) ?
1973
} ;
7bd805ff Andy McCall 11 days ago ↶
1974
1975
1976
1977
let objects: Vec< ( ObjectType, & [u8 ]) > = cp_bundle
1978
.objects
1979
.iter ( )
1980
.map ( | ( ty , body ) | ( * ty, body.as_slice ( ) ) )
1981
.collect ( ) ;
f3811eb2 Andy McCall 11 days ago ↶
1982
let t_store = crate :: timing:: phase( " shallow: store the checkpoint" ) ;
7bd805ff Andy McCall 11 days ago ↶
1983
let batch = self .store.begin_batch ( ) ? ;
1984
let stored = self .store.put_many ( & objects) ;
1985
batch.finish ( ) ? ;
f3811eb2 Andy McCall 11 days ago ↶
1986
drop ( t_store) ;
7bd805ff Andy McCall 11 days ago ↶
1987
let cp_ref = objects
1988
.iter ( )
1989
.zip ( stored? )
1990
.find ( | ( (ty , _ ) , _) | * ty = = ObjectType:: Checkpoint)
1991
.map ( | ( _, r ) | r ) ;
75167672 Andy McCall 1 month ago
1992
let Some ( cp_ref) = cp_ref else {
1993
return fail ( format! ( " {remote_name} sent no checkpoint" ) ) ;
1994
} ;
2863456a Andy McCall 1 month ago ↶
1995
self .install_checkpoint ( & bookmark, & cp_ref) ? ;
f3811eb2 Andy McCall 11 days ago ↶
1996
let _t_blobs = crate :: timing:: phase( " shallow: the binary files' blobs" ) ;
7bd805ff Andy McCall 11 days ago ↶
1997
1998
1999
2000
let cp = crate :: objects:: Checkpoint:: decode(
2001
& self .store.get_typed ( & cp_ref, ObjectType:: Checkpoint) ? ,
2002
) ? ;
2003
let base = State:: from_checkpoint_history( & self .read_blob ( & cp.payload) ? ) ? ;
2004
let mut missing: Vec< ObjectRef> = base
2005
.opaque_nodes ( )
2006
.iter ( )
2007
.flat_map ( | n | base.live_blobs ( n) )
2008
.filter ( | b | ! self .store.has ( b) )
2009
.collect ( ) ;
2010
missing.sort ( ) ;
2011
missing.dedup ( ) ;
2012
if self .config.max_blob.is_some ( ) {
2013
for b in & missing {
2014
self .register_lazy ( b, remote_name) ? ;
2015
}
2016
} else {
2017
for part in missing.chunks ( 512 ) {
2018
let objects = remote.objects ( part) ? ;
2019
let objects: Vec< ( ObjectType, & [u8 ]) > = objects
2020
.iter ( )
2021
.filter ( | ( ty , _) | matches! ( ty, ObjectType:: Blob | ObjectType:: Chunk) )
2022
.map ( | ( ty , body ) | ( * ty, body.as_slice ( ) ) )
2023
.collect ( ) ;
2024
let batch = self .store.begin_batch ( ) ? ;
2025
let stored = self .store.put_many ( & objects) ;
2026
batch.finish ( ) ? ;
2027
stored? ;
2028
}
2029
if let Some ( b) = missing.iter ( ) .find ( | b | ! self .store.has ( b) ) {
2030
return fail ( format! ( " {remote_name} did not send blob {} " , b.short ( 12 ) ) ) ;
2031
}
2032
}
f3811eb2 Andy McCall 11 days ago ↶
2033
2034
2035
2036
2037
let imported = if depth = = 0 {
2038
let mut boundary = self .boundary ( ) ;
2039
boundary.extend ( r.heads.iter ( ) .filter ( | h | ! self .store.has ( h) ) .copied ( ) ) ;
2040
self .write_boundary ( & boundary) ? ;
2041
Vec :: new( )
2042
} else {
2043
let wanted = remote.shallow ( & r.heads, depth) ? ;
2044
let bundle = remote.fetch ( & wanted, self .config.max_blob) ? ;
2045
self .import_bundle_shallow ( & bundle, false ) ?
2046
} ;
2863456a Andy McCall 1 month ago ↶
2047
if self .config.max_blob.is_some ( ) {
2048
self .register_missing_blobs ( & imported, remote_name) ? ;
2049
}
2050
self .refresh_boundary ( & imported) ? ;
2051
if let Some ( sa) = & r.attestation {
2052
let ar = self .store.put_attest ( & sa.attest) ? ;
2053
for sig in & sa.sigs {
2054
self .store.put_signature ( & ar, sig) ? ;
2055
}
2056
if let AttestBody:: Ref { serial, .. } = sa.attest.body {
2057
self .record_serial ( remote_name, & r.name, serial) ? ;
2058
}
2059
}
2060
let state = self .store.put_state ( & StateObject:: new( r.heads.clone ( ) ) ) ? ;
2061
let ( op_ref, op) = self .head_op ( ) ? ;
2062
let mut view = op.view.clone ( ) ;
75167672 Andy McCall 1 month ago
2063
view.remotes
2064
.entry ( remote_name.to_string ( ) )
2065
.or_default ( )
2066
.insert ( r.name.clone ( ) , state) ;
2067
self .record_op (
2068
& [ op_ref] ,
2069
& format! ( " oxy fetch {remote_name} --depth {depth} " ) ,
2070
view,
2071
) ? ;
2863456a Andy McCall 1 month ago ↶
2072
Ok ( imported.len ( ) )
2073
}
2074
98286406 Andy McCall 1 month ago ↶
2075
2076
2077
pub fn pull ( & self , remote_name : & str ) -> Result< PullReport> {
6caacfff Andy McCall 1 month ago ↶
2078
let _wc = self .lock_working_copy ( ) ? ;
d36ba2f7 Andy McCall 16 days ago ↶
2079
let skipped = self .fetch ( remote_name) ? .skipped;
98286406 Andy McCall 1 month ago ↶
2080
let ( op_ref, op) = self .head_op ( ) ? ;
14edbaaf Andy McCall 1 month ago ↶
2081
let current = self .config.bookmark.clone ( ) ;
2082
let mut local_current = self .heads_of ( & op.view, & current) ? ;
2083
local_current.sort ( ) ;
2084
let mut view = op.view.clone ( ) ;
2085
let mut current_heads = local_current.clone ( ) ;
2086
let mut changed = false ;
2087
let mut others = Vec :: new( ) ;
2088
let tracked = op
75167672 Andy McCall 1 month ago
2089
.view
2090
.remotes
2091
.get ( remote_name)
14edbaaf Andy McCall 1 month ago ↶
2092
.cloned ( )
2093
.unwrap_or_default ( ) ;
2094
for ( name, remote_state) in tracked {
2095
2096
2097
let local_state = op.view.bookmarks.get ( & name) .copied ( ) ;
2098
if local_state.is_none ( ) & & name ! = current {
2099
continue ;
2100
}
2101
if local_state = = Some ( remote_state) {
2102
continue ;
2103
}
2104
let local = self .heads_of ( & op.view, & name) ? ;
2105
let remote_heads = self .store.get_state ( & remote_state) ? .heads;
2106
if remote_heads.iter ( ) .all ( | h | local.contains ( h) ) {
2107
continue ;
2108
}
2109
let mut all = local.clone ( ) ;
2110
all.extend ( remote_heads) ;
2111
let st = self .load_state_history ( & all) ? ;
2112
let mut heads = st.maximal ( & all) ;
2113
heads.sort ( ) ;
2114
let mut sorted_local = local;
2115
sorted_local.sort ( ) ;
2116
if heads = = sorted_local {
2117
continue ;
2118
}
2119
view.bookmarks.insert (
2120
name.clone ( ) ,
2121
self .store.put_state ( & StateObject:: new( heads.clone ( ) ) ) ? ,
2122
) ;
2123
if name = = current {
2124
changed = true ;
2125
current_heads = heads;
2126
} else {
2127
others.push ( name) ;
2128
}
2129
}
f6dccc45 Andy McCall 26 days ago ↶
2130
if changed | | ! others.is_empty ( ) {
2131
self .record_op ( & [ op_ref] , & format! ( " oxy pull {remote_name} " ) , view) ? ;
98286406 Andy McCall 1 month ago ↶
2132
}
f6dccc45 Andy McCall 26 days ago ↶
2133
2134
2135
2136
let checked_out = self .follow_bookmark ( & current_heads, & current, " oxy pull" ) ? ;
75167672 Andy McCall 1 month ago
2137
Ok ( PullReport {
f6dccc45 Andy McCall 26 days ago ↶
2138
heads: if changed {
2139
current_heads
2140
} else {
2141
local_current
2142
} ,
14edbaaf Andy McCall 1 month ago ↶
2143
changed,
75167672 Andy McCall 1 month ago
2144
checked_out,
14edbaaf Andy McCall 1 month ago ↶
2145
others,
d36ba2f7 Andy McCall 16 days ago ↶
2146
skipped,
75167672 Andy McCall 1 month ago
2147
} )
f6dccc45 Andy McCall 26 days ago ↶
2148
}
2149
2150
2151
2152
2153
2154
2155
pub fn working_copy_behind ( & self ) -> Result< Option< usize > > {
2156
let ( _ , wc) = self .working_copy ( ) ? ;
2157
let mut base = wc.deps.clone ( ) ;
2158
base.sort ( ) ;
2159
let mut heads = self .bookmark_heads ( ) ? ;
2160
heads.sort ( ) ;
2161
if base = = heads | | heads.is_empty ( ) {
2162
return Ok ( None ) ;
2163
}
2164
let state = self .load_state_history ( & heads) ? ;
2165
if ! base.iter ( ) .all ( | h | state.contains ( h) ) {
2166
return Ok ( None ) ;
2167
}
2168
let had = if base.is_empty ( ) {
2169
0
2170
} else {
2171
self .load_state_history ( & base) ? .len ( )
2172
} ;
2173
Ok ( Some ( state.len ( ) .saturating_sub ( had) ) .filter ( | n | * n > 0 ) )
2174
}
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
pub fn follow_bookmark (
2186
& self ,
2187
heads : & [ChangeHash],
2188
bookmark : & str ,
2189
command : & str ,
2190
) -> Result< bool > {
2191
let snap = self .snapshot ( command) ? ;
2192
let clean = snap.wc.tree_ops.is_empty ( ) & & snap.wc.edits.is_empty ( ) ;
2193
let mut base = snap.base.maximal ( & snap.wc.deps) ;
2194
base.sort ( ) ;
2195
let mut target = heads.to_vec ( ) ;
2196
target.sort ( ) ;
2197
if base = = target {
2198
return Ok ( false ) ;
2199
}
2200
let state = self .load_state_history ( heads) ? ;
2201
if ! base.iter ( ) .all ( | h | state.contains ( h) ) {
2202
2203
return Ok ( false ) ;
2204
}
2205
if clean {
2206
self .checkout ( heads, false , & format! ( " {command} (checkout)" ) ) ? ;
2207
Ok ( true )
2208
} else {
2209
Ok ( self
2210
.checkout_carry ( heads, bookmark, & format! ( " {command} (checkout --carry)" ) )
2211
.is_ok ( ) )
b63fc7a7 Andy McCall 11 days ago ↶
2212
}
2213
}
2214
2215
2216
2217
2218
2219
pub fn push_tag_withdrawal ( & self , remote_name : & str , tag : & str ) -> Result< Vec< RefResult> > {
2220
let remote = self .open_named_remote ( remote_name) ? ;
2221
self .check_remote_id ( remote.as_ref ( ) , remote_name, true ) ? ;
2222
let resp = remote.refs ( ) ? ;
2223
let name = format! ( " tags/{tag} " ) ;
2224
if resp.withdrawn.iter ( ) .any ( | t | t.name = = tag ) {
2225
return Ok ( vec! [ RefResult {
2226
name,
2227
ok: true ,
2228
reason: " already withdrawn" .into ( ) ,
2229
} ] ) ;
2230
}
2231
let Some ( there) = resp.tags.iter ( ) .find ( | t | t.name = = tag ) else {
2232
return fail ( format! ( " {remote_name} has no tag {tag} " ) ) ;
2233
} ;
2234
if resp.policy.is_some ( ) & & self .secret_key ( ) ? .is_none ( ) {
2235
return fail ( format! ( " {remote_name} enforces a trust policy; withdrawing a tag needs an identity (`oxy identity create`)" ) ) ;
f6dccc45 Andy McCall 26 days ago ↶
2236
}
b63fc7a7 Andy McCall 11 days ago ↶
2237
if self .tag_withdrawal ( tag) ? .is_none ( ) {
2238
match self .view ( ) ? .tags.get ( tag) {
2239
Some ( st) if * st = = there.state => {
2240
self .tag_delete ( tag, " " ) ? ;
2241
}
2242
Some ( _ ) => {
2243
return fail ( format! (
2244
" tag {tag} names another state here than on {remote_name} "
2245
) )
2246
}
2247
None => {
2248
return fail ( format! (
2249
" there is no tag {tag} here to withdraw: `oxy fetch {remote_name} ` first"
2250
) )
2251
}
2252
}
2253
}
2254
let Some ( w) = self
2255
.withdrawn_refs ( ) ?
2256
.into_iter ( )
2257
.find ( | w | w.name = = tag & & w.state = = there.state )
2258
else {
2259
return fail ( format! (
2260
" tag {tag} was withdrawn here at another state than {remote_name} 's"
2261
) ) ;
2262
} ;
2263
let mut bundle = Bundle:: default( ) ;
2264
let signers: Vec< KeyId> = w
2265
.attestation
2266
.iter ( )
2267
.flat_map ( | a | a.sigs.iter ( ) .map ( | s | s.key ) )
2268
.collect ( ) ;
2269
for k in & signers {
2270
if let Ok ( id) = self .identity ( k) {
2271
bundle.objects.push ( ( ObjectType:: Identity, id.encode ( ) ) ) ;
2272
}
2273
}
2274
self .attach_certificates_for ( & mut bundle, & signers) ? ;
2275
remote.push ( bundle, vec! [ ] , None , vec! [ w] )
98286406 Andy McCall 1 month ago ↶
2276
}
2277
2278
2279
f8c69576 Andy McCall 1 month ago ↶
2280
2281
2282
2283
pub fn push_delete ( & self , remote_name : & str , bookmark : & str ) -> Result< Vec< RefResult> > {
b63fc7a7 Andy McCall 11 days ago ↶
2284
if let Some ( tag) = bookmark.strip_prefix ( " tags/" ) {
2285
return self .push_tag_withdrawal ( remote_name, tag) ;
2286
}
f8c69576 Andy McCall 1 month ago ↶
2287
let remote = self .open_named_remote ( remote_name) ? ;
2288
self .check_remote_id ( remote.as_ref ( ) , remote_name, true ) ? ;
2289
let resp = remote.refs ( ) ? ;
2290
let Some ( r) = resp.refs.iter ( ) .find ( | r | r.name = = bookmark ) else {
2291
return fail ( format! ( " {remote_name} has no bookmark {bookmark} " ) ) ;
2292
} ;
2293
if resp.policy.is_some ( ) & & self .secret_key ( ) ? .is_none ( ) {
2294
return fail ( format! ( " {remote_name} enforces a trust policy; deleting needs an identity (`oxy identity create`)" ) ) ;
2295
}
2296
let attestation = match self .secret_key ( ) ? {
2297
Some ( _ ) => Some ( self .sign_attest ( & Attest {
2298
repo: self .id ( ) ? ,
2299
hlc: Hlc:: now( ) ,
2300
body: AttestBody:: Ref {
2301
name: bookmark.to_string ( ) ,
2302
old_state: r.state,
2303
new_state: ObjectRef:: ZERO ,
2304
serial: r.last_serial.unwrap_or ( 0 ) + 1 ,
2305
} ,
2306
} ) ? ) ,
2307
None => None ,
2308
} ;
2309
let results = remote.push (
2310
Bundle:: default( ) ,
2311
vec! [ RefUpdate {
2312
name: bookmark.to_string ( ) ,
2313
old_state: r.state,
2314
new_state: ObjectRef:: ZERO ,
2315
force: true ,
2316
attestation,
2317
} ] ,
2318
None ,
2319
vec! [ ] ,
2320
) ? ;
2321
if results.iter ( ) .any ( | x | x.ok & & x.name = = bookmark ) {
2322
let ( op_ref, op) = self .head_op ( ) ? ;
2323
let mut view = op.view.clone ( ) ;
2324
if let Some ( m) = view.remotes.get_mut ( remote_name) {
2325
m.remove ( bookmark) ;
2326
}
2327
self .record_op (
2328
& [ op_ref] ,
2329
& format! ( " oxy push {remote_name} --delete {bookmark} " ) ,
2330
view,
2331
) ? ;
2332
}
2333
Ok ( results)
2334
}
2335
34fad4a9 Andy McCall 25 days ago ↶
2336
2337
2338
2339
2340
pub fn remove_remote ( & mut self , name : & str ) -> Result< ( ) > {
2341
if ! self .config.remotes.contains_key ( name) {
2342
return fail ( format! ( " no remote {name} : `oxy remote list` shows them" ) ) ;
2343
}
2344
let prefix = format! ( " remote.{name} ." ) ;
2345
let keys: Vec< String> = self
2346
.config
2347
.repo_layer ( )
2348
.keys ( )
2349
.filter ( | k | k.starts_with ( & prefix) )
2350
.cloned ( )
2351
.collect ( ) ;
2352
for k in keys {
2353
self .config.set ( & k, " " ) ? ;
2354
}
2355
self .config.remotes.remove ( name) ;
2356
self .save_config ( ) ? ;
2357
let ( op_ref, op) = self .head_op ( ) ? ;
2358
if op.view.remotes.contains_key ( name) {
2359
let mut view = op.view.clone ( ) ;
2360
view.remotes.remove ( name) ;
2361
self .record_op ( & [ op_ref] , & format! ( " oxy remote remove {name} " ) , view) ? ;
2362
}
2363
let mirror = self .oxy.join ( " remotes" ) .join ( name) ;
2364
if mirror.is_dir ( ) {
2365
fs:: remove_dir_all( & mirror) ? ;
2366
}
2367
Ok ( ( ) )
2368
}
2369
d3b27090 Andy McCall 11 days ago ↶
2370
2371
2372
2373
2374
2375
2376
2377
fn send_objects_ahead (
2378
& self ,
2379
remote : & dyn crate:: protocol:: Remote,
2380
remote_name : & str ,
2381
mut bundle : Bundle,
2382
progress : crate:: store:: Progress,
2383
) -> Result< Bundle> {
2384
let limit = self .config.push_batch_bytes;
2385
let changes: u64 = bundle
2386
.changes
2387
.iter ( )
2388
.map ( | ( c , _) | c.encode ( ) .len ( ) as u64 )
2389
.sum ( ) ;
2390
let objects: u64 = bundle.objects.iter ( ) .map ( | ( _, b ) | b.len ( ) as u64 ) .sum ( ) ;
2391
if changes + objects < = limit {
2392
return Ok ( bundle) ;
2393
}
2394
let ( mut kept, mut parts, mut part, mut bytes) = ( Vec :: new( ) , Vec :: new( ) , Vec :: new( ) , 0 u64 ) ;
2395
for ( ty, body) in std:: mem:: take( & mut bundle.objects) {
2396
if ! matches! ( ty, ObjectType:: Blob | ObjectType:: Chunk) {
2397
kept.push ( ( ty, body) ) ;
2398
continue ;
2399
}
2400
if ! part.is_empty ( ) & & bytes + body.len ( ) as u64 > limit {
2401
parts.push ( std:: mem:: take( & mut part) ) ;
2402
bytes = 0 ;
2403
}
2404
bytes + = body.len ( ) as u64 ;
2405
part.push ( ( ty, body) ) ;
2406
}
2407
if ! part.is_empty ( ) {
2408
parts.push ( part) ;
2409
}
2410
let n = parts.len ( ) ;
2411
for ( i, objects) in parts.into_iter ( ) .enumerate ( ) {
2412
progress ( & format! (
2413
" objects {} of {n} : {} blobs and chunks" ,
2414
i + 1 ,
2415
objects.len ( )
2416
) ) ;
2417
let results = remote.push (
2418
Bundle {
2419
objects,
2420
.. Default :: default( )
2421
} ,
2422
vec! [ ] ,
2423
None ,
2424
vec! [ ] ,
2425
) ? ;
2426
match results.iter ( ) .find ( | r | r.name = = OBJECTS_RESULT ) {
2427
Some ( r) if r.ok => { }
2428
Some ( r) => {
2429
return fail ( format! (
2430
" {remote_name} refused objects part {} of {n} : {} " ,
2431
i + 1 ,
2432
r.reason
2433
) )
2434
}
2435
None => {
2436
return fail ( format! (
2437
" {remote_name} does not take a push in parts, and this one is too large for one: update the server's oxy"
2438
) )
2439
}
2440
}
2441
}
2442
bundle.objects = kept;
2443
Ok ( bundle)
2444
}
2445
cb8b8082 Andy McCall 26 days ago ↶
2446
2447
2448
2449
fn push_batches ( & self , changes : & [ChangeHash]) -> Result< Vec< Vec< ChangeHash> > > {
2450
let blob_len = | r : & ObjectRef| -> u64 {
2451
self .store
2452
.get_typed ( r, ObjectType:: Blob)
2453
.ok ( )
2454
.and_then ( | b | Blob:: decode( & b) .ok ( ) )
2455
.map_or ( 0 , | b | b.length )
2456
} ;
2457
let ( mut out, mut batch, mut bytes) = ( Vec :: new( ) , Vec :: new( ) , 0 u64 ) ;
2458
for h in changes {
2459
let raw = self .store.get_typed ( h, ObjectType:: Change) ? ;
2460
let ( c, texts) = Change:: decode_skeleton( & raw, * h) ? ;
2461
let mut weight = raw.len ( ) as u64 ;
2462
for t in & texts {
2463
if let crate :: objects:: TextRef:: Blob( r, _ , _ ) = t {
2464
weight + = blob_len ( r) ;
2465
}
2466
}
2467
for e in & c.edits {
2468
if let Edit:: Replace { new: Some ( b) , .. } = e {
2469
weight + = blob_len ( b) ;
2470
}
2471
}
2472
if ! batch.is_empty ( ) & & bytes + weight > self .config.push_batch_bytes {
2473
out.push ( std:: mem:: take( & mut batch) ) ;
2474
bytes = 0 ;
2475
}
2476
batch.push ( * h) ;
2477
bytes + = weight;
2478
}
2479
out.push ( batch) ;
2480
Ok ( out)
2481
}
2482
98286406 Andy McCall 1 month ago ↶
2483
pub fn push ( & self , remote_name : & str , force : bool ) -> Result< Vec< RefResult> > {
6d3eefbc Andy McCall 1 month ago ↶
2484
let bookmark = self .config.bookmark.clone ( ) ;
7b9809e6 Andy McCall 1 month ago ↶
2485
self .push_bookmark ( remote_name, & bookmark, force)
2486
}
2487
2488
75167672 Andy McCall 1 month ago
2489
pub fn push_bookmark (
cb8b8082 Andy McCall 26 days ago ↶
2490
& self ,
2491
remote_name : & str ,
2492
bookmark : & str ,
2493
force : bool ,
2494
) -> Result< Vec< RefResult> > {
2495
self .push_bookmark_with ( remote_name, bookmark, force, & mut | _ | { } )
2496
}
2497
2498
2499
c8d9059e Andy McCall 10 days ago ↶
2500
2501
2502
2503
2504
pub ( crate ) fn remote_holds (
2505
& self ,
2506
refs : & [crate:: protocol:: RemoteRef],
2507
bookmark_heads : & [ChangeHash],
2508
) -> Vec< ChangeHash> {
2509
let mut have: Vec< ChangeHash> = bookmark_heads.to_vec ( ) ;
2510
for h in refs.iter ( ) .flat_map ( | r | & r.heads) {
2511
if ! have.contains ( h) & & self .store.has ( h) {
2512
have.push ( * h) ;
2513
}
2514
}
2515
have
2516
}
2517
cb8b8082 Andy McCall 26 days ago ↶
2518
pub fn push_bookmark_with (
75167672 Andy McCall 1 month ago
2519
& self ,
2520
remote_name : & str ,
2521
bookmark : & str ,
2522
force : bool ,
cb8b8082 Andy McCall 26 days ago ↶
2523
progress : crate:: store:: Progress,
75167672 Andy McCall 1 month ago
2524
) -> Result< Vec< RefResult> > {
7b9809e6 Andy McCall 1 month ago ↶
2525
let ( op_ref, op) = self .head_op ( ) ? ;
2526
if ! op.view.bookmarks.contains_key ( bookmark) {
2527
return fail ( format! ( " no bookmark {bookmark} " ) ) ;
2528
}
2529
let bookmark = bookmark.to_string ( ) ;
6d3eefbc Andy McCall 1 month ago ↶
2530
let local_heads = self .heads_of ( & op.view, & bookmark) ? ;
2531
2532
self .run_hook (
2533
" pre-push" ,
75167672 Andy McCall 1 month ago
2534
& format! (
2535
" {{ \" event\" :\" pre-push\" ,\" remote\" :{} ,\" bookmark\" :{} ,\" heads\" :{} }} " ,
2536
json_str ( remote_name) ,
2537
json_str ( & bookmark) ,
2538
json_array ( local_heads.iter ( ) .map ( | h | json_str ( & h.to_hex ( ) ) ) )
2539
) ,
6d3eefbc Andy McCall 1 month ago ↶
2540
) ? ;
98286406 Andy McCall 1 month ago ↶
2541
let remote = self .open_named_remote ( remote_name) ? ;
75167672 Andy McCall 1 month ago
2542
self .check_remote_id ( remote.as_ref ( ) , remote_name, true ) ? ;
83e0677b Andy McCall 1 month ago ↶
2543
let resp = remote.refs ( ) ? ;
2544
let local_policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp ) ;
28fc23d7 Andy McCall 1 month ago ↶
2545
let resp_policy_serial = resp.policy.as_ref ( ) .map ( | p | p.policy.serial ) ;
83e0677b Andy McCall 1 month ago ↶
2546
let policy_to_send = match ( & local_policy, & resp.policy) {
2547
( Some ( l) , Some ( r) ) if l.policy.serial > r.policy.serial => Some ( l.clone ( ) ) ,
2548
( Some ( l) , None ) => Some ( l.clone ( ) ) ,
2549
( Some ( l) , Some ( r) ) if l.policy.serial < r.policy.serial => {
75167672 Andy McCall 1 month ago
2550
return fail ( format! (
2551
" {remote_name} has a newer policy (serial {} ); fetch first" ,
2552
r.policy.serial
2553
) ) ;
83e0677b Andy McCall 1 month ago ↶
2554
}
2555
_ => None ,
2556
} ;
2557
let remote_has_policy = resp.policy.is_some ( ) | | policy_to_send.is_some ( ) ;
2558
if remote_has_policy & & self .secret_key ( ) ? .is_none ( ) {
2559
return fail ( format! ( " {remote_name} enforces a trust policy; pushing needs an identity (`oxy identity create`)" ) ) ;
2560
}
b63fc7a7 Andy McCall 11 days ago ↶
2561
let remote_tags: BTreeSet< String> = resp
2562
.tags
2563
.iter ( )
2564
.chain ( & resp.withdrawn)
2565
.map ( | t | t.name.clone ( ) )
2566
.collect ( ) ;
75167672 Andy McCall 1 month ago
2567
let tags_to_send: Vec< crate:: protocol:: TagRef> = self
2568
.tag_refs ( ) ?
2569
.into_iter ( )
2570
.filter ( | t | ! remote_tags.contains ( & t.name) )
b63fc7a7 Andy McCall 11 days ago ↶
2571
.collect ( ) ;
2572
2573
2574
let withdrawals_to_send: Vec< crate:: protocol:: TagRef> = self
2575
.withdrawn_refs ( ) ?
2576
.into_iter ( )
2577
.filter ( | w | {
2578
resp.tags
2579
.iter ( )
2580
.any ( | t | t.name = = w.name & & t.state = = w.state )
2581
} )
75167672 Andy McCall 1 month ago
2582
.collect ( ) ;
83e0677b Andy McCall 1 month ago ↶
2583
let refs = resp.refs;
98286406 Andy McCall 1 month ago ↶
2584
let empty = self .store.put_state ( & StateObject:: new( vec! [ ] ) ) ? ;
75167672 Andy McCall 1 month ago
2585
let ( remote_state, remote_heads, last_serial) =
2586
match refs.iter ( ) .find ( | r | r.name = = bookmark ) {
2587
Some ( r) => ( r.state, r.heads.clone ( ) , r.last_serial) ,
2588
None => ( empty, vec! [ ] , None ) ,
2589
} ;
2590
let new_state = self
2591
.store
2592
.put_state ( & StateObject:: new( local_heads.clone ( ) ) ) ? ;
83e0677b Andy McCall 1 month ago ↶
2593
2594
2595
2596
b63fc7a7 Andy McCall 11 days ago ↶
2597
if new_state = = remote_state
2598
& & policy_to_send.is_none ( )
2599
& & tags_to_send.is_empty ( )
2600
& & withdrawals_to_send.is_empty ( )
2601
{
75167672 Andy McCall 1 month ago
2602
return Ok ( vec! [ RefResult {
2603
name: bookmark,
2604
ok: true ,
2605
reason: " already up to date" .into ( ) ,
2606
} ] ) ;
98286406 Andy McCall 1 month ago ↶
2607
}
f3811eb2 Andy McCall 11 days ago ↶
2608
2609
2610
let boundary = self .boundary ( ) ;
98286406 Andy McCall 1 month ago ↶
2611
for h in & remote_heads {
f3811eb2 Andy McCall 11 days ago ↶
2612
if ! self .store.has ( h) & & ! boundary.contains ( h) {
75167672 Andy McCall 1 month ago
2613
return fail ( format! (
3e5772cc Andy McCall 1 month ago ↶
2614
" the remote has change {} which you do not; pull first (`oxy pull {remote_name} `), then push again" ,
75167672 Andy McCall 1 month ago
2615
h.short ( 12 )
2616
) ) ;
98286406 Andy McCall 1 month ago ↶
2617
}
2618
}
2619
if ! force {
2620
let closure = self .closure_in_store ( & local_heads) ? ;
f3811eb2 Andy McCall 11 days ago ↶
2621
if let Some ( h) = remote_heads
2622
.iter ( )
2623
.find ( | h | ! closure.contains ( h) & & ! boundary.contains ( h) )
2624
{
98286406 Andy McCall 1 month ago ↶
2625
return fail ( format! ( " not a fast-forward: remote head {} is not in your state; pull first or use --force" , h.short ( 12 ) ) ) ;
2626
}
2627
}
c8d9059e Andy McCall 10 days ago ↶
2628
let to_send = self .negotiate ( & self .remote_holds ( & refs, & remote_heads) , & local_heads) ? ;
98286406 Andy McCall 1 month ago ↶
2629
let key = self .secret_key ( ) ? .map ( | ( k , _) | k ) ;
2630
if let Some ( key) = key {
05e71ed6 Andy McCall 1 month ago ↶
2631
cb8b8082 Andy McCall 26 days ago ↶
2632
2633
98286406 Andy McCall 1 month ago ↶
2634
let mut unsigned = Vec :: new( ) ;
2635
for h in & to_send {
cb8b8082 Andy McCall 26 days ago ↶
2636
let c = self .store.get_change_meta ( h) ? ;
a2387d54 Andy McCall 18 days ago ↶
2637
if self .seals_for_author ( & c.author, & key)
75167672 Andy McCall 1 month ago
2638
& & ! matches! ( self .authenticate_change ( h) ? , SignatureStatus:: Valid { .. } )
2639
{
98286406 Andy McCall 1 month ago ↶
2640
unsigned.push ( * h) ;
2641
}
2642
}
2643
for chunk in unsigned.chunks ( crate :: attest:: MAX_SEAL_HASHES ) {
cb8b8082 Andy McCall 26 days ago ↶
2644
self .sign_attest ( & Attest:: seal( self .id ( ) ? , chunk.to_vec ( ) ) ) ? ;
98286406 Andy McCall 1 month ago ↶
2645
}
cb8b8082 Andy McCall 26 days ago ↶
2646
}
2647
2648
2649
2650
2651
let batches = self .push_batches ( & to_send) ? ;
2652
let ( last, earlier) = batches.split_last ( ) .expect ( " at least one batch" ) ;
2653
for ( i, batch) in earlier.iter ( ) .enumerate ( ) {
2654
progress ( & format! (
2655
" part {} of {} : {} changes" ,
2656
i + 1 ,
2657
batches.len ( ) ,
2658
batch.len ( )
2659
) ) ;
d3b27090 Andy McCall 11 days ago ↶
2660
let bundle = self .send_objects_ahead (
2661
remote.as_ref ( ) ,
2662
remote_name,
2663
self .bundle_for ( batch) ? ,
2664
& mut * progress,
2665
) ? ;
2666
let results = remote.push ( bundle, vec! [ ] , None , vec! [ ] ) ? ;
cb8b8082 Andy McCall 26 days ago ↶
2667
match results.iter ( ) .find ( | r | r.name = = OBJECTS_RESULT ) {
2668
Some ( r) if r.ok => { }
2669
Some ( r) => {
2670
return fail ( format! (
2671
" {remote_name} refused part {} of the push: {} " ,
2672
i + 1 ,
2673
r.reason
2674
) )
2675
}
2676
None => {
2677
return fail ( format! (
2678
" {remote_name} does not take a push in parts, and this one is too long for one: update the server's oxy"
2679
) )
2680
}
2681
}
2682
}
2683
if batches.len ( ) > 1 {
2684
progress ( & format! (
2685
" part {} of {} : {} changes" ,
2686
batches.len ( ) ,
2687
batches.len ( ) ,
2688
last.len ( )
2689
) ) ;
98286406 Andy McCall 1 month ago ↶
2690
}
d3b27090 Andy McCall 11 days ago ↶
2691
let mut bundle = self .send_objects_ahead (
2692
remote.as_ref ( ) ,
2693
remote_name,
2694
self .bundle_for ( last) ? ,
2695
& mut * progress,
2696
) ? ;
75167672 Andy McCall 1 month ago
2697
bundle.objects.push ( (
2698
ObjectType:: State,
2699
StateObject:: new( local_heads.clone ( ) ) .encode ( ) ,
2700
) ) ;
98286406 Andy McCall 1 month ago ↶
2701
let attestation = match key {
2702
Some ( _ ) => Some ( self .sign_attest ( & Attest {
2703
repo: self .id ( ) ? ,
2704
hlc: Hlc:: now( ) ,
75167672 Andy McCall 1 month ago
2705
body: AttestBody:: Ref {
2706
name: bookmark.clone ( ) ,
2707
old_state: remote_state,
2708
new_state,
f8c69576 Andy McCall 1 month ago ↶
2709
serial: next_serial ( last_serial) ,
75167672 Andy McCall 1 month ago
2710
} ,
98286406 Andy McCall 1 month ago ↶
2711
} ) ? ) ,
2712
None => None ,
2713
} ;
68a92484 Andy McCall 22 days ago ↶
2714
2715
2716
2717
if attestation.is_some ( ) {
2718
for k in [ self .signing_key ( ) , self .config.author_key]
2719
.into_iter ( )
2720
.flatten ( )
2721
{
2722
if let Ok ( id) = self .identity ( & k) {
2723
let body = id.encode ( ) ;
2724
if ! bundle
2725
.objects
2726
.iter ( )
2727
.any ( | ( t , b ) | * t = = ObjectType:: Identity & & * b = = body)
2728
{
2729
bundle.objects.push ( ( ObjectType:: Identity, body) ) ;
2730
}
2731
}
2732
}
f0a517d2 Andy McCall 18 days ago ↶
2733
2734
let signers: Vec< KeyId> = self .signing_key ( ) .into_iter ( ) .collect ( ) ;
2735
self .attach_certificates_for ( & mut bundle, & signers) ? ;
68a92484 Andy McCall 22 days ago ↶
2736
}
98286406 Andy McCall 1 month ago ↶
2737
let serial = attestation.as_ref ( ) .and_then ( | a | match a.attest.body {
2738
AttestBody:: Ref { serial, .. } => Some ( serial) ,
2739
_ => None ,
2740
} ) ;
83e0677b Andy McCall 1 month ago ↶
2741
let sent_serial = policy_to_send.as_ref ( ) .map ( | p | p.policy.serial ) ;
132b884b Andy McCall 1 month ago ↶
2742
2743
for t in & tags_to_send {
2744
let extra = self .negotiate ( & remote_heads, & t.heads) ? ;
75167672 Andy McCall 1 month ago
2745
let extra: Vec< ChangeHash> =
2746
extra.into_iter ( ) .filter ( | h | ! to_send.contains ( h) ) .collect ( ) ;
132b884b Andy McCall 1 month ago ↶
2747
if ! extra.is_empty ( ) {
2748
let more = self .bundle_for ( & extra) ? ;
2749
bundle.changes.extend ( more.changes) ;
2c75672f Andy McCall 1 month ago ↶
2750
bundle.hashes.extend ( more.hashes) ;
132b884b Andy McCall 1 month ago ↶
2751
bundle.attests.extend ( more.attests) ;
2752
bundle.objects.extend ( more.objects) ;
2753
}
75167672 Andy McCall 1 month ago
2754
bundle.objects.push ( (
2755
ObjectType:: State,
2756
StateObject:: new( t.heads.clone ( ) ) .encode ( ) ,
2757
) ) ;
132b884b Andy McCall 1 month ago ↶
2758
}
d8524a9f Andy McCall 16 days ago ↶
2759
2760
2761
2762
let tag_signers: Vec< KeyId> = tags_to_send
2763
.iter ( )
b63fc7a7 Andy McCall 11 days ago ↶
2764
.chain ( & withdrawals_to_send)
d8524a9f Andy McCall 16 days ago ↶
2765
.filter_map ( | t | t.attestation.as_ref ( ) )
2766
.flat_map ( | a | a.sigs.iter ( ) .map ( | s | s.key ) )
2767
.collect ( ) ;
2768
for k in & tag_signers {
2769
if let Ok ( id) = self .identity ( k) {
2770
let body = id.encode ( ) ;
2771
if ! bundle
2772
.objects
2773
.iter ( )
2774
.any ( | ( t , b ) | * t = = ObjectType:: Identity & & * b = = body)
2775
{
2776
bundle.objects.push ( ( ObjectType:: Identity, body) ) ;
2777
}
2778
}
2779
}
2780
if ! tag_signers.is_empty ( ) {
2781
self .attach_certificates_for ( & mut bundle, & tag_signers) ? ;
2782
}
28fc23d7 Andy McCall 1 month ago ↶
2783
if let Some ( l) = & policy_to_send {
2784
let remote_serial = resp_policy_serial;
75167672 Andy McCall 1 month ago
2785
bundle.policies = self
2786
.policy_history ( ) ?
2787
.into_iter ( )
2788
.filter ( | sp | {
2789
remote_serial.is_none_or ( | r | sp.policy.serial > r )
2790
& & sp.policy.serial < l.policy.serial
2791
} )
2792
.collect ( ) ;
28fc23d7 Andy McCall 1 month ago ↶
2793
}
75167672 Andy McCall 1 month ago
2794
let results = remote.push (
2795
bundle,
2796
vec! [ RefUpdate {
2797
name: bookmark.clone ( ) ,
2798
old_state: remote_state,
2799
new_state,
2800
force,
2801
attestation,
2802
} ] ,
2803
policy_to_send,
b63fc7a7 Andy McCall 11 days ago ↶
2804
tags_to_send
2805
.into_iter ( )
2806
.chain ( withdrawals_to_send)
2807
.collect ( ) ,
75167672 Andy McCall 1 month ago
2808
) ? ;
2809
if let ( Some ( serial) , true ) = (
2810
sent_serial,
2811
results.iter ( ) .any ( | r | r.ok & & r.name = = " policy" ) ,
2812
) {
83e0677b Andy McCall 1 month ago ↶
2813
self .record_policy_serial ( remote_name, serial) ? ;
2814
}
2815
if results.iter ( ) .any ( | r | r.ok & & r.name = = bookmark ) {
98286406 Andy McCall 1 month ago ↶
2816
let mut view = op.view.clone ( ) ;
75167672 Andy McCall 1 month ago
2817
view.remotes
2818
.entry ( remote_name.to_string ( ) )
2819
.or_default ( )
2820
.insert ( bookmark.clone ( ) , new_state) ;
98286406 Andy McCall 1 month ago ↶
2821
self .record_op ( & [ op_ref] , & format! ( " oxy push {remote_name} " ) , view) ? ;
2822
if let Some ( s) = serial {
2823
self .record_serial ( remote_name, & bookmark, s) ? ;
2824
}
2825
}
2826
Ok ( results)
2827
}
2828
2829
2830
2831
pub fn clone ( url : & str , dest : & Path) -> Result< Repo> {
7421309f Andy McCall 1 month ago ↶
2832
Self :: clone_with( url, dest, None , & [ ] )
b3c5a59a Andy McCall 1 month ago ↶
2833
}
2834
7421309f Andy McCall 1 month ago ↶
2835
2836
2837
75167672 Andy McCall 1 month ago
2838
pub fn clone_with (
2839
url : & str ,
2840
dest : & Path,
2841
max_blob : Option< u64 > ,
2842
sparse : & [String],
2843
) -> Result< Repo> {
2863456a Andy McCall 1 month ago ↶
2844
Self :: clone_full( url, dest, max_blob, sparse, None )
2845
}
2846
2847
2848
75167672 Andy McCall 1 month ago
2849
pub fn clone_shallow (
2850
url : & str ,
2851
dest : & Path,
2852
depth : u32 ,
2853
max_blob : Option< u64 > ,
2854
sparse : & [String],
2855
) -> Result< Repo> {
2863456a Andy McCall 1 month ago ↶
2856
Self :: clone_full( url, dest, max_blob, sparse, Some ( depth) )
2857
}
2858
75167672 Andy McCall 1 month ago
2859
fn clone_full (
2860
url : & str ,
2861
dest : & Path,
2862
max_blob : Option< u64 > ,
2863
sparse : & [String],
2864
depth : Option< u32 > ,
2865
) -> Result< Repo> {
d36ba2f7 Andy McCall 16 days ago ↶
2866
Ok ( Self :: clone_reporting( url, dest, max_blob, sparse, depth) ? .0 )
2867
}
2868
2869
2870
2871
2872
2873
2874
pub fn clone_reporting (
2875
url : & str ,
2876
dest : & Path,
2877
max_blob : Option< u64 > ,
2878
sparse : & [String],
2879
depth : Option< u32 > ,
2880
) -> Result< ( Repo, Vec< ( String, String) > ) > {
ff1f62fe Andy McCall 1 month ago ↶
2881
let options = crate :: credentials:: Credentials:: user( ) .options_for ( url) ;
2882
Self :: clone_using( url, dest, max_blob, sparse, depth, & options)
a07f60a3 Andy McCall 1 month ago ↶
2883
}
2884
ff1f62fe Andy McCall 1 month ago ↶
2885
2886
2887
a07f60a3 Andy McCall 1 month ago ↶
2888
pub ( crate ) fn clone_as_subrepo ( & self , url : & str , dest : & Path) -> Result< Repo> {
2889
let options = self .credentials_for ( url) ;
d36ba2f7 Andy McCall 16 days ago ↶
2890
Ok ( Self :: clone_using( url, dest, None , & [ ] , None , & options) ? .0 )
a07f60a3 Andy McCall 1 month ago ↶
2891
}
2892
2893
2894
2895
fn remote_on_same_hub ( & self , url : & str ) -> Option< String> {
2896
let origin = | u : & str | -> Option< String> {
2897
let ( scheme, rest) = u.split_once ( " ://" ) ? ;
9f9e72b9 Andy McCall 1 month ago ↶
2898
if ! matches! ( scheme, " http" | " https" ) {
2899
return None ;
2900
}
a07f60a3 Andy McCall 1 month ago ↶
2901
let host = rest.split ( ' /' ) .next ( ) ? ;
2902
Some ( format! (
2903
" {} ://{} " ,
2904
scheme.to_ascii_lowercase ( ) ,
2905
host.to_ascii_lowercase ( )
2906
) )
2907
} ;
2908
let want = origin ( url) ? ;
2909
self .config
2910
.remotes
2911
.iter ( )
2912
.find ( | ( _, u ) | origin ( u) .as_deref ( ) = = Some ( want.as_str ( ) ) )
2913
.map ( | ( name , _) | name.clone ( ) )
2914
}
2915
2916
2917
ff1f62fe Andy McCall 1 month ago ↶
2918
2919
a07f60a3 Andy McCall 1 month ago ↶
2920
pub ( crate ) fn credentials_for ( & self , url : & str ) -> RemoteOptions {
2921
match self .remote_on_same_hub ( url) {
2922
Some ( name) => RemoteOptions {
2923
repo_id: None ,
9f9e72b9 Andy McCall 1 month ago ↶
2924
cache_dir: None ,
a07f60a3 Andy McCall 1 month ago ↶
2925
.. self .remote_options ( & name)
2926
} ,
ff1f62fe Andy McCall 1 month ago ↶
2927
None => {
2928
let mut options = RemoteOptions:: default( ) ;
2929
self .fill_credentials ( url, & mut options) ;
2930
options
2931
}
a07f60a3 Andy McCall 1 month ago ↶
2932
}
2933
}
2934
2935
fn clone_using (
2936
url : & str ,
2937
dest : & Path,
2938
max_blob : Option< u64 > ,
2939
sparse : & [String],
2940
depth : Option< u32 > ,
2941
options : & RemoteOptions,
d36ba2f7 Andy McCall 16 days ago ↶
2942
) -> Result< ( Repo, Vec< ( String, String) > ) > {
a07f60a3 Andy McCall 1 month ago ↶
2943
let remote = open_remote ( url, options) ? ;
98286406 Andy McCall 1 month ago ↶
2944
let id = remote.repo_id ( ) ? ;
75167672 Andy McCall 1 month ago
2945
if id = = crate :: protocol:: UNBOUND_ID {
05e71ed6 Andy McCall 1 month ago ↶
2946
return fail ( format! (
2947
" {url} is empty and unbound: push a repository to it first"
2948
) ) ;
75167672 Andy McCall 1 month ago
2949
}
98286406 Andy McCall 1 month ago ↶
2950
let mut repo = Repo:: init_with_id( dest, id) ? ;
827281ee Andy McCall 1 month ago ↶
2951
repo.config
2952
.set ( " remote.origin.url" , & crate :: protocol:: stored_url( url) ) ? ;
b3c5a59a Andy McCall 1 month ago ↶
2953
if let Some ( m) = max_blob {
2954
repo.config.set ( " filter.max-blob" , & m.to_string ( ) ) ? ;
7421309f Andy McCall 1 month ago ↶
2955
} else if ! sparse.is_empty ( ) {
2956
repo.config.set ( " filter.max-blob" , " 0" ) ? ;
2957
}
2958
if ! sparse.is_empty ( ) {
2959
repo.config.set ( " filter.paths" , & sparse.join ( " ," ) ) ? ;
b3c5a59a Andy McCall 1 month ago ↶
2960
}
98286406 Andy McCall 1 month ago ↶
2961
repo.save_config ( ) ? ;
d36ba2f7 Andy McCall 16 days ago ↶
2962
let skipped = if let Some ( depth) = depth {
2863456a Andy McCall 1 month ago ↶
2963
repo.fetch_shallow ( " origin" , depth) ? ;
d36ba2f7 Andy McCall 16 days ago ↶
2964
Vec :: new( )
2863456a Andy McCall 1 month ago ↶
2965
} else {
d36ba2f7 Andy McCall 16 days ago ↶
2966
repo.fetch ( " origin" ) ? .skipped
2967
} ;
98286406 Andy McCall 1 month ago ↶
2968
let ( op_ref, op) = repo.head_op ( ) ? ;
d36ba2f7 Andy McCall 16 days ago ↶
2969
2970
2971
2972
let mut theirs = op.view.remotes.get ( " origin" ) .cloned ( ) .unwrap_or_default ( ) ;
2973
for ( name, _ ) in & skipped {
2974
theirs.insert ( name.clone ( ) , ObjectRef:: ZERO ) ;
2975
}
9f9e72b9 Andy McCall 1 month ago ↶
2976
2977
2978
let advertised = repo
2979
.open_named_remote ( " origin" )
2980
.ok ( )
2981
.and_then ( | r | r.refs ( ) .ok ( ) )
2982
.and_then ( | r | r.default_bookmark ) ;
14edbaaf Andy McCall 1 month ago ↶
2983
let bookmark = advertised
2984
.filter ( | b | theirs.contains_key ( b) )
2985
.or_else ( | | {
2986
theirs
2987
.contains_key ( & repo.config.bookmark)
2988
.then ( | | repo.config.bookmark.clone ( ) )
2989
} )
2990
.or_else ( | | {
2991
( theirs.len ( ) = = 1 )
2992
.then ( | | theirs.keys ( ) .next ( ) .cloned ( ) )
2993
.flatten ( )
2994
} )
2995
.unwrap_or_else ( | | repo.config.bookmark.clone ( ) ) ;
d36ba2f7 Andy McCall 16 days ago ↶
2996
if let Some ( ( _ , why) ) = skipped.iter ( ) .find ( | ( name , _) | * name = = bookmark) {
2997
return fail ( format! ( " cannot check out {bookmark} : {why} " ) ) ;
2998
}
14edbaaf Andy McCall 1 month ago ↶
2999
let initial = repo.config.bookmark.clone ( ) ;
3000
if bookmark ! = repo.config.bookmark {
3001
fs:: create_dir_all( repo.workspace_bookmark_path ( ) .parent ( ) .unwrap ( ) ) ? ;
3002
write_atomic ( & repo.workspace_bookmark_path ( ) , bookmark.as_bytes ( ) ) ? ;
3003
repo.config.bookmark = bookmark.clone ( ) ;
3004
}
3005
if let Some ( state) = theirs.get ( & bookmark) .copied ( ) {
98286406 Andy McCall 1 month ago ↶
3006
let heads = repo.store.get_state ( & state) ? .heads;
3007
let mut view = op.view.clone ( ) ;
14edbaaf Andy McCall 1 month ago ↶
3008
3009
if initial ! = bookmark & & repo.heads_of ( & view, & initial) ? .is_empty ( ) {
3010
view.bookmarks.remove ( & initial) ;
3011
}
98286406 Andy McCall 1 month ago ↶
3012
view.bookmarks.insert ( bookmark, state) ;
3013
repo.record_op ( & [ op_ref] , & format! ( " oxy clone {url} " ) , view) ? ;
3014
repo.checkout ( & heads, false , " oxy clone (checkout)" ) ? ;
3015
}
d36ba2f7 Andy McCall 16 days ago ↶
3016
Ok ( ( repo, skipped) )
f8c69576 Andy McCall 1 month ago ↶
3017
}
3018
}
3019
3020
3021
3022
3023
3024
fn next_serial ( last : Option< u64 > ) -> u64 {
3025
match last {
3026
Some ( l) => l + 1 ,
3027
None => Hlc:: now( ) .wall_ms.max ( 1 ) ,
98286406 Andy McCall 1 month ago ↶
3028
}
3029
}