5b9c6ad4 Andy McCall 1 month ago ↶
1
2
750251b2 Andy McCall 1 month ago ↶
3
4
5
6
7
5b9c6ad4 Andy McCall 1 month ago ↶
8
9
use crate :: attest:: Attest;
750251b2 Andy McCall 1 month ago ↶
10
use crate :: cbor:: { self , Value} ;
5b9c6ad4 Andy McCall 1 month ago ↶
11
use crate :: hash:: { ChangeHash, ObjectRef, ObjectType} ;
12
use crate :: identity:: Signature;
750251b2 Andy McCall 1 month ago ↶
13
use crate :: objects:: { self as o, Change, ObjectError} ;
83e0677b Andy McCall 1 month ago ↶
14
use crate :: policy:: Policy;
5b9c6ad4 Andy McCall 1 month ago ↶
15
use crate :: repo:: { Repo, RepoError, Result } ;
2b5ee371 Andy McCall 1 month ago ↶
16
use std:: path:: { Path, PathBuf} ;
17
use std:: sync:: Arc;
5b9c6ad4 Andy McCall 1 month ago ↶
18
750251b2 Andy McCall 1 month ago ↶
19
pub const CONTENT_TYPE : & str = " application/oxy-cbor" ;
20
pub const PROTOCOL_VERSION : u64 = 1 ;
21
5b9c6ad4 Andy McCall 1 month ago ↶
22
23
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
24
pub struct SignedAttest {
25
pub attest : Attest,
26
pub sigs : Vec< Signature> ,
27
}
28
83e0677b Andy McCall 1 month ago ↶
29
30
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
31
pub struct SignedPolicy {
32
pub policy : Policy,
33
pub sigs : Vec< Signature> ,
34
}
35
28fc23d7 Andy McCall 1 month ago ↶
36
impl SignedPolicy {
37
38
pub fn encode ( & self ) -> Vec< u8 > {
39
crate :: cbor:: encode( & wire:: policy_value( self ) )
40
}
41
pub fn decode ( b : & [u8 ]) -> Result< SignedPolicy> {
75167672 Andy McCall 1 month ago
42
wire:: policy_from(
43
& crate :: cbor:: decode( b) .map_err ( | e | RepoError:: Object( ObjectError:: from( e) ) ) ? ,
44
)
28fc23d7 Andy McCall 1 month ago ↶
45
}
46
}
47
132b884b Andy McCall 1 month ago ↶
48
83e0677b Andy McCall 1 month ago ↶
49
# [ derive ( Clone, Debug, Default ) ]
50
pub struct RefsResponse {
51
pub refs : Vec< RemoteRef> ,
52
pub policy : Option< SignedPolicy> ,
132b884b Andy McCall 1 month ago ↶
53
pub tags : Vec< TagRef> ,
28fc23d7 Andy McCall 1 month ago ↶
54
55
56
pub history : Vec< SignedPolicy> ,
83e0677b Andy McCall 1 month ago ↶
57
}
58
132b884b Andy McCall 1 month ago ↶
59
60
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
61
pub struct TagRef {
62
pub name : String,
63
pub state : ObjectRef,
64
pub heads : Vec< ChangeHash> ,
65
pub attestation : Option< SignedAttest> ,
66
}
67
5b9c6ad4 Andy McCall 1 month ago ↶
68
69
# [ derive ( Clone, Debug ) ]
70
pub struct RemoteRef {
71
pub name : String,
72
pub state : ObjectRef,
73
pub heads : Vec< ChangeHash> ,
74
pub attestation : Option< SignedAttest> ,
75
}
76
77
78
# [ derive ( Clone, Debug, Default ) ]
79
pub struct Bundle {
80
81
pub changes : Vec< ( Change, Vec< Signature> ) > ,
82
83
pub attests : Vec< SignedAttest> ,
84
85
pub objects : Vec< ( ObjectType, Vec< u8 > ) > ,
28fc23d7 Andy McCall 1 month ago ↶
86
87
88
pub policies : Vec< SignedPolicy> ,
5b9c6ad4 Andy McCall 1 month ago ↶
89
}
90
91
impl Bundle {
92
pub fn is_empty ( & self ) -> bool {
93
self .changes.is_empty ( ) & & self .attests.is_empty ( ) & & self .objects.is_empty ( )
94
}
95
}
96
97
98
# [ derive ( Clone, Debug ) ]
99
pub struct RefUpdate {
100
pub name : String,
101
pub old_state : ObjectRef,
102
pub new_state : ObjectRef,
103
pub force : bool ,
104
pub attestation : Option< SignedAttest> ,
105
}
106
107
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
108
pub struct RefResult {
109
pub name : String,
110
pub ok : bool ,
111
pub reason : String,
112
}
113
114
pub trait Remote {
115
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > ;
83e0677b Andy McCall 1 month ago ↶
116
fn refs ( & self ) -> Result< RefsResponse> ;
5b9c6ad4 Andy McCall 1 month ago ↶
117
118
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > ;
b3c5a59a Andy McCall 1 month ago ↶
119
120
121
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> ;
122
123
124
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > ;
2863456a Andy McCall 1 month ago ↶
125
126
127
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> ;
128
129
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > ;
132b884b Andy McCall 1 month ago ↶
130
131
132
75167672 Andy McCall 1 month ago
133
fn push (
134
& self ,
135
bundle : Bundle,
136
updates : Vec< RefUpdate> ,
137
policy : Option< SignedPolicy> ,
138
tags : Vec< TagRef> ,
139
) -> Result< Vec< RefResult> > ;
5b9c6ad4 Andy McCall 1 month ago ↶
140
}
141
750251b2 Andy McCall 1 month ago ↶
142
143
5b9c6ad4 Andy McCall 1 month ago ↶
144
145
pub struct LocalRemote {
146
pub repo : Repo,
84b9e9ac Andy McCall 1 month ago ↶
147
148
149
pub claimed_id : Option< [ u8 ; 16 ] > ,
5b9c6ad4 Andy McCall 1 month ago ↶
150
}
151
152
impl LocalRemote {
153
pub fn open ( path : & Path) -> Result< LocalRemote> {
75167672 Andy McCall 1 month ago
154
Ok ( LocalRemote {
155
repo: Repo:: open( path) ? ,
84b9e9ac Andy McCall 1 month ago ↶
156
claimed_id: None ,
75167672 Andy McCall 1 month ago
157
} )
5b9c6ad4 Andy McCall 1 month ago ↶
158
}
159
}
160
161
impl Remote for LocalRemote {
162
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > {
163
self .repo.id ( )
164
}
83e0677b Andy McCall 1 month ago ↶
165
fn refs ( & self ) -> Result< RefsResponse> {
5b9c6ad4 Andy McCall 1 month ago ↶
166
self .repo.remote_refs ( )
167
}
168
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
169
self .repo.negotiate ( have, want)
170
}
b3c5a59a Andy McCall 1 month ago ↶
171
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
172
self .repo.bundle_for_filtered ( changes, max_blob)
173
}
174
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
175
self .repo.objects_for ( refs)
5b9c6ad4 Andy McCall 1 month ago ↶
176
}
2863456a Andy McCall 1 month ago ↶
177
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> {
178
self .repo.checkpoint_bundle_for ( heads)
179
}
180
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
181
self .repo.shallow_changes ( heads, depth)
182
}
75167672 Andy McCall 1 month ago
183
fn push (
184
& self ,
185
bundle : Bundle,
186
updates : Vec< RefUpdate> ,
187
policy : Option< SignedPolicy> ,
188
tags : Vec< TagRef> ,
189
) -> Result< Vec< RefResult> > {
84b9e9ac Andy McCall 1 month ago ↶
190
if self .repo.is_unbound ( ) {
191
match self .claimed_id {
192
Some ( id) => self .repo.bind_id ( id) ? ,
eae59556 Andy McCall 1 month ago ↶
193
None => {
194
return Err ( RepoError:: Msg(
195
" the remote is unbound and this client did not say which repository it is"
196
.into ( ) ,
197
) )
198
}
84b9e9ac Andy McCall 1 month ago ↶
199
}
200
}
132b884b Andy McCall 1 month ago ↶
201
self .repo.receive_push ( bundle, updates, policy, tags)
5b9c6ad4 Andy McCall 1 month ago ↶
202
}
203
}
204
750251b2 Andy McCall 1 month ago ↶
205
206
2b5ee371 Andy McCall 1 month ago ↶
207
208
# [ derive ( Clone, Debug, Default ) ]
209
pub struct RemoteOptions {
210
211
pub token : Option< String> ,
212
213
214
pub ca : Option< PathBuf> ,
75167672 Andy McCall 1 month ago
215
216
217
pub repo_id : Option< [ u8 ; 16 ] > ,
2b5ee371 Andy McCall 1 month ago ↶
218
}
219
75167672 Andy McCall 1 month ago
220
221
pub const REPO_ID_HEADER : & str = " Oxy-Repo-Id" ;
222
223
224
pub const UNBOUND_ID : [ u8 ; 16 ] = [ 0 ; 16 ] ;
225
750251b2 Andy McCall 1 month ago ↶
226
227
pub struct HttpRemote {
228
base : String,
229
token : Option< String> ,
75167672 Andy McCall 1 month ago
230
repo_id : Option< [ u8 ; 16 ] > ,
750251b2 Andy McCall 1 month ago ↶
231
agent : ureq:: Agent,
232
}
233
2b5ee371 Andy McCall 1 month ago ↶
234
235
fn tls_client_config ( ca : Option< & Path> ) -> Result< Arc< rustls:: ClientConfig> > {
236
let mut roots = rustls:: RootCertStore:: empty( ) ;
237
roots.extend ( webpki_roots:: TLS_SERVER_ROOTS .iter ( ) .cloned ( ) ) ;
238
if let Some ( path) = ca {
75167672 Andy McCall 1 month ago
239
let pem = std:: fs:: read( path)
240
.map_err ( | e | RepoError:: Msg( format! ( " reading CA file {} : {e} " , path.display ( ) ) ) ) ? ;
2b5ee371 Andy McCall 1 month ago ↶
241
let certs = rustls_pemfile:: certs( & mut pem.as_slice ( ) )
242
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( )
243
.map_err ( | e | RepoError:: Msg( format! ( " parsing CA file {} : {e} " , path.display ( ) ) ) ) ? ;
244
if certs.is_empty ( ) {
75167672 Andy McCall 1 month ago
245
return Err ( RepoError:: Msg( format! (
246
" CA file {} holds no certificates" ,
247
path.display ( )
248
) ) ) ;
2b5ee371 Andy McCall 1 month ago ↶
249
}
250
for c in certs {
75167672 Andy McCall 1 month ago
251
roots
252
.add ( c)
253
.map_err ( | e | RepoError:: Msg( format! ( " CA file {} : {e} " , path.display ( ) ) ) ) ? ;
2b5ee371 Andy McCall 1 month ago ↶
254
}
255
}
75167672 Andy McCall 1 month ago
256
let cfg = rustls:: ClientConfig:: builder_with_provider( Arc:: new(
257
rustls:: crypto:: ring:: default_provider( ) ,
258
) )
259
.with_safe_default_protocol_versions ( )
260
.map_err ( | e | RepoError:: Msg( e.to_string ( ) ) ) ?
261
.with_root_certificates ( roots)
262
.with_no_client_auth ( ) ;
2b5ee371 Andy McCall 1 month ago ↶
263
Ok ( Arc:: new( cfg) )
264
}
265
750251b2 Andy McCall 1 month ago ↶
266
impl HttpRemote {
2b5ee371 Andy McCall 1 month ago ↶
267
pub fn new ( base : & str , options : & RemoteOptions) -> Result< HttpRemote> {
75167672 Andy McCall 1 month ago
268
let agent = ureq:: AgentBuilder:: new( )
269
.tls_config ( tls_client_config ( options.ca.as_deref ( ) ) ? )
270
.build ( ) ;
271
Ok ( HttpRemote {
272
base: base.trim_end_matches ( ' /' ) .to_string ( ) ,
273
token: options.token.clone ( ) ,
274
repo_id: options.repo_id,
275
agent,
276
} )
750251b2 Andy McCall 1 month ago ↶
277
}
278
279
fn call ( & self , post : bool , endpoint : & str , body : Option< & [ u8 ] > ) -> Result< Vec< u8 > > {
280
let url = format! ( " {} /oxy/v1/{endpoint} " , self .base) ;
75167672 Andy McCall 1 month ago
281
let mut req = if post {
282
self .agent.post ( & url)
283
} else {
284
self .agent.get ( & url)
285
} ;
750251b2 Andy McCall 1 month ago ↶
286
req = req.set ( " Accept" , CONTENT_TYPE ) ;
287
if let Some ( t) = & self .token {
288
req = req.set ( " Authorization" , & format! ( " Bearer {t} " ) ) ;
289
}
75167672 Andy McCall 1 month ago
290
if let Some ( id) = & self .repo_id {
291
req = req.set ( REPO_ID_HEADER , & hex:: encode( id) ) ;
292
}
750251b2 Andy McCall 1 month ago ↶
293
let resp = match body {
294
Some ( b) => req.set ( " Content-Type" , CONTENT_TYPE ) .send_bytes ( b) ,
295
None => req.call ( ) ,
296
} ;
297
match resp {
298
Ok ( r) => {
299
let mut out = Vec :: new( ) ;
75167672 Andy McCall 1 month ago
300
r.into_reader ( )
301
.read_to_end ( & mut out)
302
.map_err ( | e | RepoError:: Msg( format! ( " {url} : {e} " ) ) ) ? ;
750251b2 Andy McCall 1 month ago ↶
303
Ok ( out)
304
}
305
Err ( ureq:: Error:: Status( code, r) ) => {
306
let text = r.into_string ( ) .unwrap_or_default ( ) ;
3e5772cc Andy McCall 1 month ago ↶
307
let msg = format! ( " {url} : HTTP {code} : {} " , text.trim ( ) ) ;
308
Err ( RepoError:: Msg( with_hint ( msg) ) )
750251b2 Andy McCall 1 month ago ↶
309
}
3e5772cc Andy McCall 1 month ago ↶
310
311
Err ( e) => Err ( RepoError:: Msg( with_hint ( e.to_string ( ) ) ) ) ,
750251b2 Andy McCall 1 month ago ↶
312
}
313
}
314
}
315
3e5772cc Andy McCall 1 month ago ↶
316
317
pub fn hint_for ( message : & str ) -> Option< & 'static str > {
318
let m = message.to_ascii_lowercase ( ) ;
319
let hint = if m.contains ( " http 401" ) {
320
" the server did not accept the token: set one with `oxy config remote.<remote>.token TOKEN` (a personal access token; pushing needs repo:write)"
321
} else if m.contains ( " http 403" ) {
322
" the token or account lacks permission: pushing needs a token with repo:write and write access to the repository"
323
} else if m.contains ( " http 404" ) {
324
" nothing at this URL: check the owner and repository name, or create the repository on the hub first"
325
} else if m.contains ( " unknownissuer" )
326
| | m.contains ( " unknown issuer" )
327
| | m.contains ( " certificate" )
328
| | m.contains ( " invalidcertificate" )
329
{
330
" the server's certificate is not trusted: for a hub with a self-signed certificate, download it from /.well-known/oxyhub-ca.pem on the hub and run `oxy config remote.<remote>.ca FILE`"
331
} else if m.contains ( " connection refused" ) {
332
" nothing is listening there: check the URL and port, and that the server is running"
333
} else if m.contains ( " dns" )
334
| | m.contains ( " failed to lookup" )
335
| | m.contains ( " name or service not known" )
336
{
337
" the host name does not resolve: check the URL"
338
} else if m.contains ( " timed out" ) | | m.contains ( " timeout" ) {
339
" the server did not answer in time: check the network, or try again"
340
} else {
341
return None ;
342
} ;
343
Some ( hint)
344
}
345
346
347
pub fn with_hint ( message : String) -> String {
348
match hint_for ( & message) {
349
Some ( h) => format! ( " {message} \n hint: {h} " ) ,
350
None => message,
351
}
352
}
353
d82e4409 Andy McCall 1 month ago ↶
354
355
356
pub fn http_get ( url : & str , options : & RemoteOptions) -> Result< Vec< u8 > > {
357
let agent = ureq:: AgentBuilder:: new( )
358
.tls_config ( tls_client_config ( options.ca.as_deref ( ) ) ? )
359
.build ( ) ;
360
let mut req = agent.get ( url) .set ( " Accept" , " application/json" ) ;
361
if let Some ( t) = & options.token {
362
req = req.set ( " Authorization" , & format! ( " Bearer {t} " ) ) ;
363
}
364
match req.call ( ) {
365
Ok ( r) => {
366
let mut out = Vec :: new( ) ;
367
r.into_reader ( )
368
.read_to_end ( & mut out)
369
.map_err ( | e | RepoError:: Msg( format! ( " {url} : {e} " ) ) ) ? ;
370
Ok ( out)
371
}
372
Err ( ureq:: Error:: Status( code, r) ) => {
373
let text = r.into_string ( ) .unwrap_or_default ( ) ;
3e5772cc Andy McCall 1 month ago ↶
374
Err ( RepoError:: Msg( with_hint ( format! (
4213c41d Andy McCall 1 month ago ↶
375
" {url} : HTTP {code} : {} " ,
376
text.trim ( )
3e5772cc Andy McCall 1 month ago ↶
377
) ) ) )
d82e4409 Andy McCall 1 month ago ↶
378
}
3e5772cc Andy McCall 1 month ago ↶
379
380
Err ( e) => Err ( RepoError:: Msg( with_hint ( e.to_string ( ) ) ) ) ,
d82e4409 Andy McCall 1 month ago ↶
381
}
382
}
383
750251b2 Andy McCall 1 month ago ↶
384
impl Remote for HttpRemote {
385
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > {
386
wire:: decode_capabilities( & self .call ( false , " capabilities" , None ) ? )
387
}
83e0677b Andy McCall 1 month ago ↶
388
fn refs ( & self ) -> Result< RefsResponse> {
750251b2 Andy McCall 1 month ago ↶
389
Ok ( wire:: decode_refs( & self .call ( false , " refs" , None ) ? ) ? .1 )
390
}
391
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
75167672 Andy McCall 1 month ago
392
wire:: decode_hashes( & self .call (
393
true ,
394
" negotiate" ,
395
Some ( & wire:: encode_negotiate( have, want) ) ,
396
) ? )
750251b2 Andy McCall 1 month ago ↶
397
}
b3c5a59a Andy McCall 1 month ago ↶
398
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
75167672 Andy McCall 1 month ago
399
wire:: decode_bundle( & self .call (
400
true ,
401
" fetch" ,
402
Some ( & wire:: encode_fetch( changes, max_blob) ) ,
403
) ? )
750251b2 Andy McCall 1 month ago ↶
404
}
b3c5a59a Andy McCall 1 month ago ↶
405
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
75167672 Andy McCall 1 month ago
406
Ok (
407
wire:: decode_bundle( & self .call ( true , " objects" , Some ( & wire:: encode_hashes( refs) ) ) ? ) ?
408
.objects,
409
)
b3c5a59a Andy McCall 1 month ago ↶
410
}
2863456a Andy McCall 1 month ago ↶
411
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> {
412
wire:: decode_bundle( & self .call ( true , " checkpoint" , Some ( & wire:: encode_hashes( heads) ) ) ? )
413
}
414
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
75167672 Andy McCall 1 month ago
415
wire:: decode_hashes( & self .call (
416
true ,
417
" shallow" ,
418
Some ( & wire:: encode_shallow( heads, depth) ) ,
419
) ? )
2863456a Andy McCall 1 month ago ↶
420
}
75167672 Andy McCall 1 month ago
421
fn push (
422
& self ,
423
bundle : Bundle,
424
updates : Vec< RefUpdate> ,
425
policy : Option< SignedPolicy> ,
426
tags : Vec< TagRef> ,
427
) -> Result< Vec< RefResult> > {
428
wire:: decode_push_response( & self .call (
429
true ,
430
" push" ,
431
Some ( & wire:: encode_push(
432
& bundle,
433
& updates,
434
policy.as_ref ( ) ,
435
& tags,
436
) ) ,
437
) ? )
750251b2 Andy McCall 1 month ago ↶
438
}
439
}
440
441
2b5ee371 Andy McCall 1 month ago ↶
442
pub fn open_remote ( url : & str , options : & RemoteOptions) -> Result< Box< dyn Remote> > {
750251b2 Andy McCall 1 month ago ↶
443
if url.starts_with ( " http://" ) | | url.starts_with ( " https://" ) {
2b5ee371 Andy McCall 1 month ago ↶
444
return Ok ( Box :: new( HttpRemote:: new( url, options) ? ) ) ;
750251b2 Andy McCall 1 month ago ↶
445
}
5b9c6ad4 Andy McCall 1 month ago ↶
446
let path = url.strip_prefix ( " file://" ) .unwrap_or ( url) ;
447
if path.contains ( " ://" ) {
750251b2 Andy McCall 1 month ago ↶
448
return Err ( RepoError:: Msg( format! ( " unsupported remote URL {url:?} " ) ) ) ;
5b9c6ad4 Andy McCall 1 month ago ↶
449
}
84b9e9ac Andy McCall 1 month ago ↶
450
let mut local = LocalRemote:: open( Path:: new( path) ) ? ;
451
local.claimed_id = options.repo_id;
452
Ok ( Box :: new( local) )
5b9c6ad4 Andy McCall 1 month ago ↶
453
}
750251b2 Andy McCall 1 month ago ↶
454
455
456
457
458
pub mod wire {
459
use super :: * ;
460
461
fn schema ( msg : & str ) -> RepoError {
462
RepoError:: Object( ObjectError:: Schema( msg.into ( ) ) )
463
}
464
fn sigs_value ( sigs : & [Signature]) -> Value {
465
Value:: Array( sigs.iter ( ) .map ( | s | s.to_value ( ) ) .collect ( ) )
466
}
467
fn sigs_from ( v : & Value) -> Result< Vec< Signature> > {
75167672 Andy McCall 1 month ago
468
Ok ( o:: array( v, " signatures" ) ?
469
.iter ( )
470
.map ( Signature:: from_value)
471
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( ) ? )
750251b2 Andy McCall 1 month ago ↶
472
}
473
fn hashes_value ( hs : & [ObjectRef]) -> Value {
474
Value:: Array( hs.iter ( ) .map ( | h | Value:: Bytes( h.0. to_vec ( ) ) ) .collect ( ) )
475
}
476
fn hashes_from ( v : & Value) -> Result< Vec< ObjectRef> > {
75167672 Andy McCall 1 month ago
477
Ok ( o:: array( v, " hashes" ) ?
478
.iter ( )
479
.map ( | h | o:: oref( h, " hash" ) )
480
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( ) ? )
750251b2 Andy McCall 1 month ago ↶
481
}
482
fn attest_value ( sa : & SignedAttest) -> Value {
483
Value:: Array( vec! [ Value:: Bytes( sa.attest.encode ( ) ) , sigs_value ( & sa.sigs) ] )
484
}
485
fn attest_from ( v : & Value) -> Result< SignedAttest> {
486
let a = o:: array( v, " signed attest" ) ? ;
487
if a.len ( ) ! = 2 {
488
return Err ( schema ( " signed attest: expected [attest, sigs]" ) ) ;
489
}
75167672 Andy McCall 1 month ago
490
Ok ( SignedAttest {
491
attest: Attest:: decode( o:: bytes( & a[ 0 ] , " attest" ) ? ) ? ,
492
sigs: sigs_from ( & a[ 1 ] ) ? ,
493
} )
750251b2 Andy McCall 1 month ago ↶
494
}
495
fn opt_attest_value ( sa : & Option< SignedAttest> ) -> Value {
496
sa.as_ref ( ) .map ( attest_value) .unwrap_or ( Value:: Null)
497
}
498
fn opt_attest_from ( v : & Value) -> Result< Option< SignedAttest> > {
75167672 Andy McCall 1 month ago
499
if v.is_null ( ) {
500
Ok ( None )
501
} else {
502
attest_from ( v) .map ( Some )
503
}
750251b2 Andy McCall 1 month ago ↶
504
}
28fc23d7 Andy McCall 1 month ago ↶
505
506
507
pub fn policy_value ( sp : & SignedPolicy) -> Value {
508
Value:: Array( vec! [ Value:: Bytes( sp.policy.encode ( ) ) , sigs_value ( & sp.sigs) ] )
83e0677b Andy McCall 1 month ago ↶
509
}
28fc23d7 Andy McCall 1 month ago ↶
510
pub fn policy_from ( v : & Value) -> Result< SignedPolicy> {
83e0677b Andy McCall 1 month ago ↶
511
let a = o:: array( v, " signed policy" ) ? ;
512
if a.len ( ) ! = 2 {
513
return Err ( schema ( " signed policy: expected [policy, sigs]" ) ) ;
514
}
75167672 Andy McCall 1 month ago
515
Ok ( SignedPolicy {
516
policy: Policy:: decode( o:: bytes( & a[ 0 ] , " policy" ) ? ) ? ,
517
sigs: sigs_from ( & a[ 1 ] ) ? ,
518
} )
28fc23d7 Andy McCall 1 month ago ↶
519
}
520
fn opt_policy_value ( sp : Option< & SignedPolicy> ) -> Value {
521
sp.map ( policy_value) .unwrap_or ( Value:: Null)
522
}
523
fn opt_policy_from ( v : & Value) -> Result< Option< SignedPolicy> > {
75167672 Andy McCall 1 month ago
524
if v.is_null ( ) {
525
Ok ( None )
526
} else {
527
policy_from ( v) .map ( Some )
528
}
83e0677b Andy McCall 1 month ago ↶
529
}
750251b2 Andy McCall 1 month ago ↶
530
fn map < 'a > ( v : & 'a Value, what : & str ) -> Result< & 'a o:: Map> {
531
Ok ( o:: map( v, what) ? )
532
}
533
fn field < 'a > ( m : & 'a o:: Map, k : u64 , what : & str ) -> Result< & 'a Value> {
534
Ok ( o:: field( m, k, what) ? )
535
}
536
6f8aeb99 Andy McCall 1 month ago ↶
537
538
539
750251b2 Andy McCall 1 month ago ↶
540
pub fn bundle_value ( b : & Bundle) -> Value {
6f8aeb99 Andy McCall 1 month ago ↶
541
let mut changes = Vec :: with_capacity( b.changes.len ( ) ) ;
542
let mut texts: Vec< ( ObjectType, Vec< u8 > ) > = Vec :: new( ) ;
543
let mut listed: Option< std:: collections:: HashSet< ObjectRef> > = None ;
544
for ( c, s) in & b.changes {
545
let ( bytes, stored) = c.encode_parts ( ) ;
546
for t in stored {
547
let listed = listed.get_or_insert_with ( | | {
548
b.objects
549
.iter ( )
550
.map ( | ( ty , body ) | crate :: hash:: hash_object( * ty, body) )
551
.collect ( )
552
} ) ;
553
if ! listed.insert ( t.blob.hash ( ) ) {
554
continue ;
555
}
556
for chunk in crate :: chunk:: chunks( & t.content) {
557
if listed.insert ( crate :: hash:: hash_object( ObjectType:: Chunk, chunk) ) {
558
texts.push ( ( ObjectType:: Chunk, chunk.to_vec ( ) ) ) ;
559
}
560
}
561
texts.push ( ( ObjectType:: Blob, t.blob.encode ( ) ) ) ;
562
}
563
changes.push ( Value:: Array( vec! [ Value:: Bytes( bytes) , sigs_value ( s) ] ) ) ;
564
}
750251b2 Andy McCall 1 month ago ↶
565
Value:: map( [
6f8aeb99 Andy McCall 1 month ago ↶
566
( 0 , Value:: Array( changes) ) ,
750251b2 Andy McCall 1 month ago ↶
567
(
75167672 Andy McCall 1 month ago
568
1 ,
569
Value:: Array( b.attests.iter ( ) .map ( attest_value) .collect ( ) ) ,
570
) ,
571
(
750251b2 Andy McCall 1 month ago ↶
572
2 ,
573
Value:: Array(
75167672 Andy McCall 1 month ago
574
b.objects
575
.iter ( )
6f8aeb99 Andy McCall 1 month ago ↶
576
.chain ( & texts)
75167672 Andy McCall 1 month ago
577
.map ( | ( t , body ) | {
578
Value:: Array( vec! [
579
Value:: Text( t.name ( ) .into ( ) ) ,
580
Value:: Bytes( body.clone ( ) ) ,
581
] )
582
} )
583
.collect ( ) ,
750251b2 Andy McCall 1 month ago ↶
584
) ,
585
) ,
75167672 Andy McCall 1 month ago
586
(
587
3 ,
588
Value:: Array( b.policies.iter ( ) .map ( policy_value) .collect ( ) ) ,
589
) ,
750251b2 Andy McCall 1 month ago ↶
590
] )
591
}
592
593
pub fn bundle_from_value ( v : & Value) -> Result< Bundle> {
594
let m = map ( v, " bundle" ) ? ;
595
let mut b = Bundle:: default( ) ;
596
for ob in o:: array( field ( m, 2 , " objects" ) ? , " objects" ) ? {
597
let pair = o:: array( ob, " object" ) ? ;
598
if pair.len ( ) ! = 2 {
599
return Err ( schema ( " object: expected [type, body]" ) ) ;
600
}
75167672 Andy McCall 1 month ago
601
let ty = ObjectType:: from_name( o:: text( & pair[ 0 ] , " object type" ) ? )
602
.ok_or_else ( | | schema ( " unknown object type" ) ) ? ;
603
b.objects
604
.push ( ( ty, o:: bytes( & pair[ 1 ] , " object body" ) ? .to_vec ( ) ) ) ;
6f8aeb99 Andy McCall 1 month ago ↶
605
}
606
607
let mut by_ref: Option< std:: collections:: HashMap< ObjectRef, usize > > = None ;
608
for c in o:: array( field ( m, 0 , " changes" ) ? , " changes" ) ? {
609
let pair = o:: array( c, " change entry" ) ? ;
610
if pair.len ( ) ! = 2 {
611
return Err ( schema ( " change entry: expected [change, sigs]" ) ) ;
612
}
613
let change = Change:: decode_with( o:: bytes( & pair[ 0 ] , " change" ) ? , & mut | text, count| {
614
let by_ref = by_ref.get_or_insert_with ( | | {
615
b.objects
616
.iter ( )
617
.enumerate ( )
618
.map ( | ( i , (ty , body ) ) | ( crate :: hash:: hash_object( * ty, body) , i) )
619
.collect ( )
620
} ) ;
621
let get =
622
| r : & ObjectRef, want : ObjectType| match by_ref.get ( r) .map ( | i | & b.objects[ * i] ) {
623
Some ( ( ty, body) ) if * ty = = want => Ok ( body) ,
624
_ => Err ( ObjectError:: Schema( format! (
625
" the bundle lacks {} {} " ,
626
want.name ( ) ,
627
r.short ( 12 )
628
) ) ) ,
629
} ;
630
let blob = crate :: objects:: Blob:: decode( get ( text, ObjectType:: Blob) ? ) ? ;
631
let mut content = Vec :: with_capacity( blob.length as usize ) ;
632
for chunk in & blob.chunks {
633
content.extend_from_slice ( get ( chunk, ObjectType:: Chunk) ? ) ;
634
}
635
crate :: objects:: text_lines( & content, count)
636
} ) ? ;
637
b.changes.push ( ( change, sigs_from ( & pair[ 1 ] ) ? ) ) ;
638
}
639
for a in o:: array( field ( m, 1 , " attests" ) ? , " attests" ) ? {
640
b.attests.push ( attest_from ( a) ? ) ;
750251b2 Andy McCall 1 month ago ↶
641
}
28fc23d7 Andy McCall 1 month ago ↶
642
if let Some ( ps) = m.get ( & 3 ) {
643
for p in o:: array( ps, " policies" ) ? {
644
b.policies.push ( policy_from ( p) ? ) ;
645
}
646
}
750251b2 Andy McCall 1 month ago ↶
647
Ok ( b)
648
}
649
650
pub fn encode_bundle ( b : & Bundle) -> Vec< u8 > {
651
cbor:: encode( & bundle_value ( b) )
652
}
653
pub fn decode_bundle ( bytes : & [u8 ]) -> Result< Bundle> {
654
bundle_from_value ( & cbor:: decode( bytes) .map_err ( ObjectError:: from) ? )
655
}
656
657
pub fn encode_capabilities ( id : [u8 ; 16]) -> Vec< u8 > {
658
cbor:: encode( & Value:: map( [
659
( 0 , Value:: Array( vec! [ Value:: Uint( PROTOCOL_VERSION ) ] ) ) ,
660
( 1 , Value:: Bytes( id.to_vec ( ) ) ) ,
661
( 2 , Value:: Array( vec! [ Value:: Text( " seal" .into ( ) ) ] ) ) ,
662
] ) )
663
}
664
pub fn decode_capabilities ( bytes : & [u8 ]) -> Result< [ u8 ; 16 ] > {
665
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
666
let m = map ( & v, " capabilities" ) ? ;
667
let versions = o:: array( field ( m, 0 , " versions" ) ? , " versions" ) ? ;
75167672 Andy McCall 1 month ago
668
if ! versions
669
.iter ( )
670
.any ( | x | x.as_uint ( ) = = Some ( PROTOCOL_VERSION ) )
671
{
672
return Err ( RepoError:: Msg(
673
" remote does not speak protocol version 1" .into ( ) ,
674
) ) ;
750251b2 Andy McCall 1 month ago ↶
675
}
75167672 Andy McCall 1 month ago
676
o:: bytes( field ( m, 1 , " repo id" ) ? , " repo id" ) ?
677
.try_into ( )
678
.map_err ( | _| schema ( " repo id: expected 16 bytes" ) )
750251b2 Andy McCall 1 month ago ↶
679
}
680
132b884b Andy McCall 1 month ago ↶
681
fn tags_value ( tags : & [TagRef]) -> Value {
682
Value:: Array(
683
tags.iter ( )
684
.map ( | t | {
685
Value:: map( [
686
( 0 , Value:: Text( t.name.clone ( ) ) ) ,
687
( 1 , Value:: Bytes( t.state.0. to_vec ( ) ) ) ,
688
( 2 , hashes_value ( & t.heads) ) ,
689
( 3 , opt_attest_value ( & t.attestation) ) ,
690
] )
691
} )
692
.collect ( ) ,
693
)
694
}
695
fn tags_from ( v : & Value) -> Result< Vec< TagRef> > {
696
let mut out = Vec :: new( ) ;
697
for t in o:: array( v, " tags" ) ? {
698
let tm = map ( t, " tag" ) ? ;
699
out.push ( TagRef {
700
name: o:: text( field ( tm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
701
state: o:: oref( field ( tm, 1 , " state" ) ? , " state" ) ? ,
702
heads: hashes_from ( field ( tm, 2 , " heads" ) ? ) ? ,
703
attestation: opt_attest_from ( field ( tm, 3 , " attestation" ) ? ) ? ,
704
} ) ;
705
}
706
Ok ( out)
707
}
708
83e0677b Andy McCall 1 month ago ↶
709
pub fn encode_refs ( id : [u8 ; 16], resp : & RefsResponse) -> Vec< u8 > {
750251b2 Andy McCall 1 month ago ↶
710
cbor:: encode( & Value:: map( [
711
(
712
0 ,
713
Value:: Array(
83e0677b Andy McCall 1 month ago ↶
714
resp.refs
715
.iter ( )
750251b2 Andy McCall 1 month ago ↶
716
.map ( | r | {
717
Value:: map( [
718
( 0 , Value:: Text( r.name.clone ( ) ) ) ,
719
( 1 , Value:: Bytes( r.state.0. to_vec ( ) ) ) ,
720
( 2 , hashes_value ( & r.heads) ) ,
721
( 3 , opt_attest_value ( & r.attestation) ) ,
722
( 4 , r.last_serial.map ( Value:: Uint) .unwrap_or ( Value:: Null) ) ,
723
] )
724
} )
725
.collect ( ) ,
726
) ,
727
) ,
728
( 1 , Value:: Bytes( id.to_vec ( ) ) ) ,
83e0677b Andy McCall 1 month ago ↶
729
( 2 , opt_policy_value ( resp.policy.as_ref ( ) ) ) ,
132b884b Andy McCall 1 month ago ↶
730
( 3 , tags_value ( & resp.tags) ) ,
75167672 Andy McCall 1 month ago
731
(
732
4 ,
733
Value:: Array( resp.history.iter ( ) .map ( policy_value) .collect ( ) ) ,
734
) ,
750251b2 Andy McCall 1 month ago ↶
735
] ) )
736
}
83e0677b Andy McCall 1 month ago ↶
737
pub fn decode_refs ( bytes : & [u8 ]) -> Result< ( [u8 ; 16], RefsResponse) > {
750251b2 Andy McCall 1 month ago ↶
738
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
739
let m = map ( & v, " refs" ) ? ;
75167672 Andy McCall 1 month ago
740
let id: [ u8 ; 16 ] = o:: bytes( field ( m, 1 , " repo id" ) ? , " repo id" ) ?
741
.try_into ( )
742
.map_err ( | _| schema ( " repo id: expected 16 bytes" ) ) ? ;
750251b2 Andy McCall 1 month ago ↶
743
let mut refs = Vec :: new( ) ;
744
for r in o:: array( field ( m, 0 , " refs" ) ? , " refs" ) ? {
745
let rm = map ( r, " ref" ) ? ;
746
let ls = field ( rm, 4 , " last serial" ) ? ;
747
refs.push ( RemoteRef {
748
name: o:: text( field ( rm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
749
state: o:: oref( field ( rm, 1 , " state" ) ? , " state" ) ? ,
750
heads: hashes_from ( field ( rm, 2 , " heads" ) ? ) ? ,
751
attestation: opt_attest_from ( field ( rm, 3 , " attestation" ) ? ) ? ,
75167672 Andy McCall 1 month ago
752
last_serial: if ls.is_null ( ) {
753
None
754
} else {
755
Some ( o:: uint( ls, " last serial" ) ? )
756
} ,
750251b2 Andy McCall 1 month ago ↶
757
} ) ;
758
}
83e0677b Andy McCall 1 month ago ↶
759
let policy = match m.get ( & 2 ) {
760
Some ( p) => opt_policy_from ( p) ? ,
761
None => None ,
762
} ;
132b884b Andy McCall 1 month ago ↶
763
let tags = match m.get ( & 3 ) {
764
Some ( t) => tags_from ( t) ? ,
765
None => Vec :: new( ) ,
766
} ;
28fc23d7 Andy McCall 1 month ago ↶
767
let mut history = Vec :: new( ) ;
768
if let Some ( h) = m.get ( & 4 ) {
769
for p in o:: array( h, " history" ) ? {
770
history.push ( policy_from ( p) ? ) ;
771
}
772
}
75167672 Andy McCall 1 month ago
773
Ok ( (
774
id,
775
RefsResponse {
776
refs,
777
policy,
778
tags,
779
history,
780
} ,
781
) )
750251b2 Andy McCall 1 month ago ↶
782
}
783
784
pub fn encode_negotiate ( have : & [ChangeHash], want : & [ChangeHash]) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
785
cbor:: encode( & Value:: map( [
786
( 0 , hashes_value ( have) ) ,
787
( 1 , hashes_value ( want) ) ,
788
] ) )
750251b2 Andy McCall 1 month ago ↶
789
}
790
pub fn decode_negotiate ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , Vec< ChangeHash> ) > {
791
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
792
let m = map ( & v, " negotiate" ) ? ;
75167672 Andy McCall 1 month ago
793
Ok ( (
794
hashes_from ( field ( m, 0 , " have" ) ? ) ? ,
795
hashes_from ( field ( m, 1 , " want" ) ? ) ? ,
796
) )
750251b2 Andy McCall 1 month ago ↶
797
}
798
b3c5a59a Andy McCall 1 month ago ↶
799
800
pub fn encode_fetch ( hs : & [ChangeHash], max_blob : Option< u64 > ) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
801
cbor:: encode( & Value:: map( [
802
( 0 , hashes_value ( hs) ) ,
803
( 1 , max_blob.map ( Value:: Uint) .unwrap_or ( Value:: Null) ) ,
804
] ) )
b3c5a59a Andy McCall 1 month ago ↶
805
}
806
pub fn decode_fetch ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , Option< u64 > ) > {
807
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
808
let m = map ( & v, " fetch" ) ? ;
809
let max = match m.get ( & 1 ) {
810
Some ( x) if ! x.is_null ( ) => Some ( o:: uint( x, " max blob" ) ? ) ,
811
_ => None ,
812
} ;
813
Ok ( ( hashes_from ( field ( m, 0 , " changes" ) ? ) ? , max) )
814
}
815
2863456a Andy McCall 1 month ago ↶
816
817
pub fn encode_shallow ( hs : & [ChangeHash], depth : u32 ) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
818
cbor:: encode( & Value:: map( [
819
( 0 , hashes_value ( hs) ) ,
820
( 1 , Value:: Uint( depth as u64 ) ) ,
821
] ) )
2863456a Andy McCall 1 month ago ↶
822
}
823
pub fn decode_shallow ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , u32 ) > {
824
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
825
let m = map ( & v, " shallow" ) ? ;
75167672 Andy McCall 1 month ago
826
Ok ( (
827
hashes_from ( field ( m, 0 , " heads" ) ? ) ? ,
828
o:: u32_( field ( m, 1 , " depth" ) ? , " depth" ) ? ,
829
) )
2863456a Andy McCall 1 month ago ↶
830
}
831
750251b2 Andy McCall 1 month ago ↶
832
pub fn encode_hashes ( hs : & [ChangeHash]) -> Vec< u8 > {
833
cbor:: encode( & Value:: map( [ ( 0 , hashes_value ( hs) ) ] ) )
834
}
835
pub fn decode_hashes ( bytes : & [u8 ]) -> Result< Vec< ChangeHash> > {
836
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
837
hashes_from ( field ( map ( & v, " hashes" ) ? , 0 , " hashes" ) ? )
838
}
839
75167672 Andy McCall 1 month ago
840
pub fn encode_push (
841
bundle : & Bundle,
842
updates : & [RefUpdate],
843
policy : Option< & SignedPolicy> ,
844
tags : & [TagRef],
845
) -> Vec< u8 > {
750251b2 Andy McCall 1 month ago ↶
846
cbor:: encode( & Value:: map( [
847
( 0 , bundle_value ( bundle) ) ,
83e0677b Andy McCall 1 month ago ↶
848
( 2 , opt_policy_value ( policy) ) ,
132b884b Andy McCall 1 month ago ↶
849
( 3 , tags_value ( tags) ) ,
750251b2 Andy McCall 1 month ago ↶
850
(
851
1 ,
852
Value:: Array(
853
updates
854
.iter ( )
855
.map ( | u | {
856
Value:: map( [
857
( 0 , Value:: Text( u.name.clone ( ) ) ) ,
858
( 1 , Value:: Bytes( u.old_state.0. to_vec ( ) ) ) ,
859
( 2 , Value:: Bytes( u.new_state.0. to_vec ( ) ) ) ,
860
( 3 , Value:: Bool( u.force) ) ,
861
( 4 , opt_attest_value ( & u.attestation) ) ,
862
] )
863
} )
864
.collect ( ) ,
865
) ,
866
) ,
867
] ) )
868
}
132b884b Andy McCall 1 month ago ↶
869
870
pub type PushParts = ( Bundle, Vec< RefUpdate> , Option< SignedPolicy> , Vec< TagRef> ) ;
871
872
pub fn decode_push ( bytes : & [u8 ]) -> Result< PushParts> {
750251b2 Andy McCall 1 month ago ↶
873
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
874
let m = map ( & v, " push" ) ? ;
875
let bundle = bundle_from_value ( field ( m, 0 , " bundle" ) ? ) ? ;
876
let mut updates = Vec :: new( ) ;
877
for u in o:: array( field ( m, 1 , " updates" ) ? , " updates" ) ? {
878
let um = map ( u, " update" ) ? ;
879
updates.push ( RefUpdate {
880
name: o:: text( field ( um, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
881
old_state: o:: oref( field ( um, 1 , " old_state" ) ? , " old_state" ) ? ,
882
new_state: o:: oref( field ( um, 2 , " new_state" ) ? , " new_state" ) ? ,
75167672 Andy McCall 1 month ago
883
force: field ( um, 3 , " force" ) ?
884
.as_bool ( )
885
.ok_or_else ( | | schema ( " force: expected bool" ) ) ? ,
750251b2 Andy McCall 1 month ago ↶
886
attestation: opt_attest_from ( field ( um, 4 , " attestation" ) ? ) ? ,
887
} ) ;
888
}
83e0677b Andy McCall 1 month ago ↶
889
let policy = match m.get ( & 2 ) {
890
Some ( p) => opt_policy_from ( p) ? ,
891
None => None ,
892
} ;
132b884b Andy McCall 1 month ago ↶
893
let tags = match m.get ( & 3 ) {
894
Some ( t) => tags_from ( t) ? ,
895
None => Vec :: new( ) ,
896
} ;
897
Ok ( ( bundle, updates, policy, tags) )
750251b2 Andy McCall 1 month ago ↶
898
}
899
900
pub fn encode_push_response ( results : & [RefResult]) -> Vec< u8 > {
901
cbor:: encode( & Value:: map( [ (
902
0 ,
903
Value:: Array(
904
results
905
.iter ( )
75167672 Andy McCall 1 month ago
906
.map ( | r | {
907
Value:: map( [
908
( 0 , Value:: Text( r.name.clone ( ) ) ) ,
909
( 1 , Value:: Bool( r.ok) ) ,
910
( 2 , Value:: Text( r.reason.clone ( ) ) ) ,
911
] )
912
} )
750251b2 Andy McCall 1 month ago ↶
913
.collect ( ) ,
914
) ,
915
) ] ) )
916
}
917
pub fn decode_push_response ( bytes : & [u8 ]) -> Result< Vec< RefResult> > {
918
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
919
let m = map ( & v, " push response" ) ? ;
920
let mut out = Vec :: new( ) ;
921
for r in o:: array( field ( m, 0 , " results" ) ? , " results" ) ? {
922
let rm = map ( r, " result" ) ? ;
923
out.push ( RefResult {
924
name: o:: text( field ( rm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
75167672 Andy McCall 1 month ago
925
ok: field ( rm, 1 , " ok" ) ?
926
.as_bool ( )
927
.ok_or_else ( | | schema ( " ok: expected bool" ) ) ? ,
750251b2 Andy McCall 1 month ago ↶
928
reason: o:: text( field ( rm, 2 , " reason" ) ? , " reason" ) ? .to_owned ( ) ,
929
} ) ;
930
}
931
Ok ( out)
932
}
933
}
934
935
# [ cfg ( test ) ]
936
mod tests {
937
use super :: * ;
938
use crate :: attest:: AttestBody;
939
use crate :: objects:: Hlc;
940
941
# [ test ]
942
fn wire_round_trips ( ) {
943
let c = crate :: objects:: tests:: sample_change( ) ;
75167672 Andy McCall 1 month ago
944
let sk = crate :: identity:: SecretKey {
945
ed_seed: [ 1 ; 32 ] ,
946
ml_seed: [ 2 ; 32 ] ,
947
} ;
750251b2 Andy McCall 1 month ago ↶
948
let id = sk.identity ( " a" , " b" , 0 ) ;
949
let key = id.hash ( ) ;
950
let sig = sk.sign ( crate :: identity:: Domain:: Change, & key, & c.hash ( ) ) ;
951
let seal = Attest:: seal( [ 3 ; 16 ] , vec! [ c.hash ( ) ] ) ;
952
let seal_sig = sk.sign ( crate :: identity:: Domain:: Attest, & key, & seal.hash ( ) ) ;
28fc23d7 Andy McCall 1 month ago ↶
953
let policy = Policy:: single_root( [ 3 ; 16 ] , id.clone ( ) , 99 ) ;
954
let psig = sk.sign ( crate :: identity:: Domain:: Policy, & key, & policy.hash ( ) ) ;
750251b2 Andy McCall 1 month ago ↶
955
let bundle = Bundle {
956
changes: vec! [ ( c.clone ( ) , vec! [ sig.clone ( ) ] ) ] ,
75167672 Andy McCall 1 month ago
957
attests: vec! [ SignedAttest {
958
attest: seal.clone ( ) ,
959
sigs: vec! [ seal_sig] ,
960
} ] ,
961
objects: vec! [
962
( ObjectType:: Identity, id.encode ( ) ) ,
963
( ObjectType:: Chunk, b " xyz" .to_vec ( ) ) ,
964
] ,
965
policies: vec! [ SignedPolicy {
966
policy: policy.clone ( ) ,
967
sigs: vec! [ psig.clone ( ) ] ,
968
} ] ,
750251b2 Andy McCall 1 month ago ↶
969
} ;
970
let d = wire:: decode_bundle( & wire:: encode_bundle( & bundle) ) .unwrap ( ) ;
971
assert_eq! ( d.changes, bundle.changes) ;
972
assert_eq! ( d.attests, bundle.attests) ;
973
assert_eq! ( d.objects, bundle.objects) ;
28fc23d7 Andy McCall 1 month ago ↶
974
assert_eq! ( d.policies, bundle.policies) ;
750251b2 Andy McCall 1 month ago ↶
975
75167672 Andy McCall 1 month ago
976
let att = Attest {
977
repo: [ 3 ; 16 ] ,
978
hlc: Hlc:: default( ) ,
979
body: AttestBody:: Ref {
980
name: " main" .into ( ) ,
981
old_state: ObjectRef( [ 1 ; 32 ] ) ,
982
new_state: ObjectRef( [ 2 ; 32 ] ) ,
983
serial: 4 ,
984
} ,
985
} ;
750251b2 Andy McCall 1 month ago ↶
986
let refs = vec! [
75167672 Andy McCall 1 month ago
987
RemoteRef {
988
name: " main" .into ( ) ,
989
state: ObjectRef( [ 2 ; 32 ] ) ,
990
heads: vec! [ c.hash ( ) ] ,
991
attestation: Some ( SignedAttest {
992
attest: att.clone ( ) ,
993
sigs: vec! [ sig.clone ( ) ] ,
994
} ) ,
995
last_serial: Some ( 4 ) ,
996
} ,
997
RemoteRef {
998
name: " dev" .into ( ) ,
999
state: ObjectRef( [ 5 ; 32 ] ) ,
1000
heads: vec! [ ] ,
1001
attestation: None ,
1002
last_serial: None ,
1003
} ,
750251b2 Andy McCall 1 month ago ↶
1004
] ;
75167672 Andy McCall 1 month ago
1005
let tag = TagRef {
1006
name: " v1" .into ( ) ,
1007
state: ObjectRef( [ 2 ; 32 ] ) ,
1008
heads: vec! [ c.hash ( ) ] ,
1009
attestation: None ,
1010
} ;
1011
let resp = RefsResponse {
1012
refs,
1013
policy: Some ( SignedPolicy {
1014
policy: policy.clone ( ) ,
1015
sigs: vec! [ psig.clone ( ) ] ,
1016
} ) ,
1017
tags: vec! [ tag.clone ( ) ] ,
1018
history: vec! [ SignedPolicy {
1019
policy: policy.clone ( ) ,
1020
sigs: vec! [ ] ,
1021
} ] ,
1022
} ;
83e0677b Andy McCall 1 month ago ↶
1023
let ( id_back, back) = wire:: decode_refs( & wire:: encode_refs( [ 3 ; 16 ] , & resp) ) .unwrap ( ) ;
750251b2 Andy McCall 1 month ago ↶
1024
assert_eq! ( id_back, [ 3 ; 16 ] ) ;
83e0677b Andy McCall 1 month ago ↶
1025
assert_eq! ( back.refs.len ( ) , 2 ) ;
1026
assert_eq! ( back.refs[ 0 ] .attestation.as_ref ( ) .unwrap ( ) .attest, att) ;
1027
assert_eq! ( back.refs[ 1 ] .last_serial, None ) ;
1028
assert_eq! ( back.policy.as_ref ( ) .unwrap ( ) .policy, policy) ;
28fc23d7 Andy McCall 1 month ago ↶
1029
assert_eq! ( back.history, resp.history) ;
132b884b Andy McCall 1 month ago ↶
1030
assert_eq! ( back.tags, vec! [ tag.clone ( ) ] ) ;
750251b2 Andy McCall 1 month ago ↶
1031
75167672 Andy McCall 1 month ago
1032
let ( h, w) = wire:: decode_negotiate( & wire:: encode_negotiate(
1033
& [ ObjectRef( [ 1 ; 32 ] ) ] ,
1034
& [ ObjectRef( [ 2 ; 32 ] ) ] ,
1035
) )
1036
.unwrap ( ) ;
750251b2 Andy McCall 1 month ago ↶
1037
assert_eq! ( ( h, w) , ( vec! [ ObjectRef( [ 1 ; 32 ] ) ] , vec! [ ObjectRef( [ 2 ; 32 ] ) ] ) ) ;
75167672 Andy McCall 1 month ago
1038
assert_eq! (
1039
wire:: decode_hashes( & wire:: encode_hashes( & [ c.hash ( ) ] ) ) .unwrap ( ) ,
1040
vec! [ c.hash ( ) ]
1041
) ;
1042
assert_eq! (
1043
wire:: decode_fetch( & wire:: encode_fetch( & [ c.hash ( ) ] , Some ( 4096 ) ) ) .unwrap ( ) ,
1044
( vec! [ c.hash ( ) ] , Some ( 4096 ) )
1045
) ;
1046
assert_eq! (
1047
wire:: decode_fetch( & wire:: encode_fetch( & [ ] , None ) ) .unwrap ( ) ,
1048
( vec! [ ] , None )
1049
) ;
1050
assert_eq! (
1051
wire:: decode_shallow( & wire:: encode_shallow( & [ c.hash ( ) ] , 3 ) ) .unwrap ( ) ,
1052
( vec! [ c.hash ( ) ] , 3 )
1053
) ;
b3c5a59a Andy McCall 1 month ago ↶
1054
75167672 Andy McCall 1 month ago
1055
assert_eq! (
1056
wire:: decode_fetch( & wire:: encode_hashes( & [ c.hash ( ) ] ) ) .unwrap ( ) ,
1057
( vec! [ c.hash ( ) ] , None )
1058
) ;
750251b2 Andy McCall 1 month ago ↶
1059
75167672 Andy McCall 1 month ago
1060
let up = RefUpdate {
1061
name: " main" .into ( ) ,
1062
old_state: ObjectRef( [ 1 ; 32 ] ) ,
1063
new_state: ObjectRef( [ 2 ; 32 ] ) ,
1064
force: true ,
1065
attestation: Some ( SignedAttest {
1066
attest: att,
1067
sigs: vec! [ sig] ,
1068
} ) ,
1069
} ;
1070
let sp = SignedPolicy {
1071
policy,
1072
sigs: vec! [ psig] ,
1073
} ;
1074
let ( b2, ups, pol, tags) = wire:: decode_push( & wire:: encode_push(
1075
& bundle,
1076
std:: slice:: from_ref( & up) ,
1077
Some ( & sp) ,
1078
std:: slice:: from_ref( & tag) ,
1079
) )
1080
.unwrap ( ) ;
83e0677b Andy McCall 1 month ago ↶
1081
assert_eq! ( pol, Some ( sp) ) ;
132b884b Andy McCall 1 month ago ↶
1082
assert_eq! ( tags, vec! [ tag] ) ;
750251b2 Andy McCall 1 month ago ↶
1083
assert_eq! ( b2.changes.len ( ) , 1 ) ;
1084
assert_eq! ( ups[ 0 ] .name, " main" ) ;
1085
assert! ( ups[ 0 ] .force) ;
1086
assert_eq! ( ups[ 0 ] .attestation, up.attestation) ;
75167672 Andy McCall 1 month ago
1087
let res = vec! [ RefResult {
1088
name: " main" .into ( ) ,
1089
ok: false ,
1090
reason: " stale" .into ( ) ,
1091
} ] ;
1092
assert_eq! (
1093
wire:: decode_push_response( & wire:: encode_push_response( & res) ) .unwrap ( ) ,
1094
res
1095
) ;
1096
assert_eq! (
1097
wire:: decode_capabilities( & wire:: encode_capabilities( [ 7 ; 16 ] ) ) .unwrap ( ) ,
1098
[ 7 ; 16 ]
1099
) ;
750251b2 Andy McCall 1 month ago ↶
1100
}
1101
}