@@ -6,7 +6,7 @@ use crate::storage::PackageInfo;
6
6
use anyhow:: { anyhow, Context , Result } ;
7
7
use bytes:: Bytes ;
8
8
use futures_util:: { Stream , StreamExt , TryStreamExt } ;
9
- use indexmap:: IndexMap ;
9
+ use indexmap:: { IndexMap , IndexSet } ;
10
10
use reqwest:: { Body , IntoUrl } ;
11
11
use secrecy:: Secret ;
12
12
use semver:: { Version , VersionReq } ;
71
71
ignore_federation_hints : bool ,
72
72
auto_accept_federation_hints : bool ,
73
73
disable_interactive : bool ,
74
+ keyring_backend : Option < String > ,
75
+ keys : IndexSet < String > ,
74
76
}
75
77
76
78
impl < R : RegistryStorage , C : ContentStorage , N : NamespaceMapStorage > Client < R , C , N > {
@@ -86,6 +88,8 @@ impl<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage> Client<R, C,
86
88
ignore_federation_hints : bool ,
87
89
auto_accept_federation_hints : bool ,
88
90
disable_interactive : bool ,
91
+ keyring_backend : Option < String > ,
92
+ keys : IndexSet < String > ,
89
93
) -> ClientResult < Self > {
90
94
let api = api:: Client :: new ( url, auth_token) ?;
91
95
Ok ( Self {
@@ -96,6 +100,8 @@ impl<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage> Client<R, C,
96
100
ignore_federation_hints,
97
101
auto_accept_federation_hints,
98
102
disable_interactive,
103
+ keyring_backend,
104
+ keys,
99
105
} )
100
106
}
101
107
@@ -311,6 +317,47 @@ impl<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage> Client<R, C,
311
317
res
312
318
}
313
319
320
+ /// Submits the provided publish information or, if not provided, loads from client
321
+ /// storage. Uses the keyring to retrieve a key and sign.
322
+ ///
323
+ /// If there's no publishing information in client storage, an error is returned.
324
+ ///
325
+ /// Returns the identifier of the record that was published.
326
+ ///
327
+ /// Use `wait_for_publish` to wait for the record to transition to the `published` state.
328
+ #[ cfg( feature = "keyring" ) ]
329
+ pub async fn sign_with_keyring_and_publish (
330
+ & self ,
331
+ publish_info : Option < PublishInfo > ,
332
+ ) -> ClientResult < RecordId > {
333
+ let publish_info = if let Some ( publish_info) = publish_info {
334
+ publish_info
335
+ } else {
336
+ self . registry
337
+ . load_publish ( )
338
+ . await ?
339
+ . ok_or ( ClientError :: NotPublishing ) ?
340
+ } ;
341
+
342
+ let registry_domain = self
343
+ . get_warg_registry ( publish_info. name . namespace ( ) )
344
+ . await ?;
345
+ let signing_key = keyring:: Keyring :: new (
346
+ self . keyring_backend
347
+ . as_deref ( )
348
+ . unwrap_or ( keyring:: Keyring :: DEFAULT_BACKEND ) ,
349
+ ) ?
350
+ . get_signing_key (
351
+ registry_domain. map ( |domain| domain. to_string ( ) ) . as_deref ( ) ,
352
+ & self . keys ,
353
+ Some ( & self . url ( ) . to_string ( ) ) ,
354
+ ) ?;
355
+
356
+ let res = self . publish_with_info ( & signing_key, publish_info) . await ;
357
+ self . registry . store_publish ( None ) . await ?;
358
+ res
359
+ }
360
+
314
361
/// Submits the provided publish information.
315
362
///
316
363
/// Any publish information in client storage is ignored.
@@ -1344,6 +1391,12 @@ impl FileSystemClient {
1344
1391
let disable_interactive =
1345
1392
cfg ! ( not( feature = "cli-interactive" ) ) || config. disable_interactive ;
1346
1393
1394
+ let ( keyring_backend, keys) = if cfg ! ( feature = "keyring" ) {
1395
+ ( config. keyring_backend . clone ( ) , config. keys . clone ( ) )
1396
+ } else {
1397
+ ( None , IndexSet :: new ( ) )
1398
+ } ;
1399
+
1347
1400
#[ cfg( feature = "keyring" ) ]
1348
1401
if auth_token. is_none ( ) && config. keyring_auth {
1349
1402
auth_token = crate :: keyring:: Keyring :: from_config ( config) ?. get_auth_token ( & url) ?
@@ -1358,6 +1411,8 @@ impl FileSystemClient {
1358
1411
config. ignore_federation_hints ,
1359
1412
config. auto_accept_federation_hints ,
1360
1413
disable_interactive,
1414
+ keyring_backend,
1415
+ keys,
1361
1416
) ?) )
1362
1417
}
1363
1418
@@ -1399,6 +1454,12 @@ impl FileSystemClient {
1399
1454
let disable_interactive =
1400
1455
cfg ! ( not( feature = "cli-interactive" ) ) || config. disable_interactive ;
1401
1456
1457
+ let ( keyring_backend, keys) = if cfg ! ( feature = "keyring" ) {
1458
+ ( config. keyring_backend . clone ( ) , config. keys . clone ( ) )
1459
+ } else {
1460
+ ( None , IndexSet :: new ( ) )
1461
+ } ;
1462
+
1402
1463
#[ cfg( feature = "keyring" ) ]
1403
1464
if auth_token. is_none ( ) && config. keyring_auth {
1404
1465
auth_token =
@@ -1414,6 +1475,8 @@ impl FileSystemClient {
1414
1475
config. ignore_federation_hints ,
1415
1476
config. auto_accept_federation_hints ,
1416
1477
disable_interactive,
1478
+ keyring_backend,
1479
+ keys,
1417
1480
)
1418
1481
}
1419
1482
0 commit comments