aspera-cli 4.26.1 → 4.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +19 -1
- data/CONTRIBUTING.md +2 -5
- data/bin/ascli +2 -2
- data/lib/aspera/agent/direct.rb +1 -1
- data/lib/aspera/agent/factory.rb +4 -0
- data/lib/aspera/agent/httpgw.rb +1 -1
- data/lib/aspera/agent/node.rb +2 -2
- data/lib/aspera/api/aoc.rb +43 -36
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/faspex.rb +7 -6
- data/lib/aspera/api/node.rb +7 -7
- data/lib/aspera/ascmd.rb +4 -4
- data/lib/aspera/ascp/installation.rb +6 -2
- data/lib/aspera/cli/context.rb +58 -0
- data/lib/aspera/cli/extended_value.rb +3 -2
- data/lib/aspera/cli/formatter.rb +83 -184
- data/lib/aspera/cli/http.rb +167 -0
- data/lib/aspera/cli/manager.rb +3 -2
- data/lib/aspera/cli/plugins/alee.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +78 -67
- data/lib/aspera/cli/plugins/ats.rb +16 -16
- data/lib/aspera/cli/plugins/base.rb +18 -12
- data/lib/aspera/cli/plugins/config.rb +166 -438
- data/lib/aspera/cli/plugins/console.rb +7 -7
- data/lib/aspera/cli/plugins/cos.rb +2 -2
- data/lib/aspera/cli/plugins/factory.rb +3 -0
- data/lib/aspera/cli/plugins/faspex.rb +21 -21
- data/lib/aspera/cli/plugins/faspex5.rb +64 -44
- data/lib/aspera/cli/plugins/faspio.rb +1 -1
- data/lib/aspera/cli/plugins/httpgw.rb +2 -2
- data/lib/aspera/cli/plugins/node.rb +79 -79
- data/lib/aspera/cli/plugins/orchestrator.rb +21 -26
- data/lib/aspera/cli/plugins/preview.rb +9 -9
- data/lib/aspera/cli/plugins/server.rb +7 -7
- data/lib/aspera/cli/plugins/shares.rb +2 -2
- data/lib/aspera/cli/preset_manager.rb +235 -0
- data/lib/aspera/cli/result.rb +310 -0
- data/lib/aspera/cli/{main.rb → runner.rb} +14 -155
- data/lib/aspera/cli/sync_actions.rb +14 -10
- data/lib/aspera/cli/terminal_formatter.rb +65 -0
- data/lib/aspera/cli/transfer_progress.rb +6 -6
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +5 -6
- data/lib/aspera/command_line_builder.rb +1 -1
- data/lib/aspera/data_repository.rb +4 -0
- data/lib/aspera/dot_container.rb +1 -1
- data/lib/aspera/environment.rb +22 -3
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/json_rpc.rb +6 -5
- data/lib/aspera/keychain/base.rb +1 -1
- data/lib/aspera/keychain/encrypted_hash.rb +1 -1
- data/lib/aspera/keychain/factory.rb +1 -1
- data/lib/aspera/keychain/macos_security.rb +1 -1
- data/lib/aspera/log.rb +6 -2
- data/lib/aspera/nagios.rb +2 -2
- data/lib/aspera/oauth/base.rb +5 -5
- data/lib/aspera/oauth/boot.rb +43 -0
- data/lib/aspera/oauth/factory.rb +37 -13
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/oauth.rb +1 -0
- data/lib/aspera/persistency_action_once.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -0
- data/lib/aspera/products/connect.rb +3 -0
- data/lib/aspera/products/transferd.rb +2 -2
- data/lib/aspera/proxy_auto_config.rb +3 -3
- data/lib/aspera/rest.rb +8 -4
- data/lib/aspera/rest_error_analyzer.rb +4 -0
- data/lib/aspera/rest_list.rb +10 -3
- data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +14 -4
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +827 -88
- data/lib/aspera/schema/async_tables.yaml +361 -0
- data/lib/aspera/schema/reader.rb +1 -1
- data/lib/aspera/schema/registry.rb +13 -6
- data/lib/aspera/secret_hider.rb +4 -0
- data/lib/aspera/sync/database.rb +14 -10
- data/lib/aspera/sync/operations.rb +5 -5
- data/lib/aspera/temp_file_manager.rb +4 -0
- data/lib/aspera/transfer/parameters.rb +4 -4
- data/lib/aspera/transfer/resumer.rb +1 -1
- data/lib/aspera/transfer/spec.schema.yaml +17 -8
- data/lib/aspera/transfer/uri.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +21 -14
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3959459dc4ecd6fbc28e485b7665744293691d275d7597375b9ee2e80dfb9477
|
|
4
|
+
data.tar.gz: 62fe6561296d5a6f35473e7c7e831a3089e54fecdbd364a4042e01f993db180e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95a052413af5c03a31e74c5b71f359b4dcd7f2af34e59be7c5c2fb49af862b45ce76be92d464419da1c9c944e1d140cd5b957a72916f53384e95317faf08fbcf
|
|
7
|
+
data.tar.gz: ed1aaa7ac2079839f69b506044ca7129e16cc4eb2c371d3311deb598aa91c6ed22c15bac03f8398062768cbdfc8131dc4fcafe84b637ce2a8357fb8c3af5c515
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# Changes (Release notes)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 4.26.2
|
|
4
|
+
|
|
5
|
+
Released: 2026-07-17
|
|
6
|
+
|
|
7
|
+
### New Features
|
|
8
|
+
|
|
9
|
+
* `faspex5`: New commands `admin file_processing` and `packages file_processing`.
|
|
10
|
+
* `aoc`: Command `user settings` now support `create`, `delete`, `list`, `show`, `modify`.
|
|
11
|
+
* `aoc`: New command `network_policy` and `configuration_policy` in `admin`.
|
|
12
|
+
* `sync` : New command `admin query` to execute an arbitrary SQL command on the snap DB.
|
|
13
|
+
* `sync` : Option `sql` to add arbitrary SQL suffixes to sync actions with snapshot DB.
|
|
14
|
+
|
|
15
|
+
### Issues Fixed
|
|
16
|
+
|
|
17
|
+
* `aoc`: Fixed `admin application membership create`.
|
|
18
|
+
|
|
19
|
+
### Breaking Changes
|
|
20
|
+
|
|
21
|
+
**global**: Replaced option `--bash-comp` with `config completion bash`.
|
|
4
22
|
|
|
5
23
|
## 4.26.1
|
|
6
24
|
|
data/CONTRIBUTING.md
CHANGED
|
@@ -72,7 +72,7 @@ The `aspera-cli` architecture is designed to be modular and extensible.
|
|
|
72
72
|
|
|
73
73
|
- **Entry Point**:
|
|
74
74
|
|
|
75
|
-
`lib/aspera/cli/
|
|
75
|
+
`lib/aspera/cli/runner.rb` contains the core CLI startup logic.
|
|
76
76
|
|
|
77
77
|
- **Plugins**:
|
|
78
78
|
|
|
@@ -112,15 +112,12 @@ The following environment variables and macros control specific build behaviors:
|
|
|
112
112
|
| `LOG_SECRETS` | `yes`/`no` | Toggles the logging of secrets in `rake` tasks. |
|
|
113
113
|
| `LOG_LEVEL` | `debug`, ... | Sets the logging verbosity for `rake` tasks. |
|
|
114
114
|
| `ENABLE_COVERAGE` | set/unset | Enables test coverage analysis when defined. |
|
|
115
|
-
| `SIGNING_KEY` | File path
|
|
116
|
-
| `SIGNING_KEY_PEM` | PEM Value | The PEM content of the signing key. |
|
|
115
|
+
| `SIGNING_KEY` | File path or PEM | Path to the signing key file, or PEM content (starts with `-----BEGIN`). |
|
|
117
116
|
| `DRY_RUN` | `1` | Simulates execution without performing actual operations (`git`, `gh`). |
|
|
118
117
|
| `DEBUG` | `1` | Shows stack trace on errors during documentation generation. |
|
|
119
118
|
|
|
120
119
|
These values can be set as standard environment variables or passed directly to the `rake` command.
|
|
121
120
|
|
|
122
|
-
Setting `SIGNING_KEY_PEM` automatically generates a file at `$HOME/.gem/signing_key.pem` and sets the `SIGNING_KEY` variable accordingly.
|
|
123
|
-
|
|
124
121
|
> [!NOTE]
|
|
125
122
|
> `ASPERA_CLI_TEST_CONF_URL` is typically defined in your shell profile for development, while others are usually for ad-hoc command-line use.
|
|
126
123
|
|
data/bin/ascli
CHANGED
data/lib/aspera/agent/direct.rb
CHANGED
|
@@ -294,7 +294,7 @@ module Aspera
|
|
|
294
294
|
Log.log.debug{"before select, timeout: #{@spawn_timeout_sec}"}
|
|
295
295
|
readable, _, _ = IO.select([mgt_server_socket], nil, nil, @spawn_timeout_sec)
|
|
296
296
|
Log.log.debug('after select, before accept')
|
|
297
|
-
Aspera.assert(readable,
|
|
297
|
+
Aspera.assert(readable, 'timeout waiting mgt port connect (select not readable)', type: Transfer::Error)
|
|
298
298
|
# There is a connection to accept
|
|
299
299
|
client_socket, _client_addrinfo = mgt_server_socket.accept
|
|
300
300
|
Log.log.debug('after accept')
|
data/lib/aspera/agent/factory.rb
CHANGED
data/lib/aspera/agent/httpgw.rb
CHANGED
|
@@ -32,7 +32,7 @@ module Aspera
|
|
|
32
32
|
# HTTP download only supports file list
|
|
33
33
|
# :reek:UnusedParameters token_regenerator
|
|
34
34
|
def start_transfer(transfer_spec, token_regenerator: nil)
|
|
35
|
-
Aspera.assert(!@gw_api.nil
|
|
35
|
+
Aspera.assert(!@gw_api.nil?, 'GW URL must be set')
|
|
36
36
|
Aspera.assert_type(transfer_spec['paths'], Array){'paths'}
|
|
37
37
|
Aspera.assert_type(transfer_spec['token'], String){'only token based transfer is supported in GW'}
|
|
38
38
|
Log.dump(:user_spec, transfer_spec)
|
data/lib/aspera/agent/node.rb
CHANGED
|
@@ -30,7 +30,7 @@ module Aspera
|
|
|
30
30
|
@root_id = root_id
|
|
31
31
|
rest_params = {base_url: url}
|
|
32
32
|
if OAuth::Factory.bearer_auth?(password)
|
|
33
|
-
Aspera.assert(!@root_id.nil
|
|
33
|
+
Aspera.assert(!@root_id.nil?, 'root_id not allowed for access key')
|
|
34
34
|
rest_params[:headers] = Api::Node.bearer_headers(password, access_key: username)
|
|
35
35
|
else
|
|
36
36
|
rest_params[:auth] = {
|
|
@@ -117,7 +117,7 @@ module Aspera
|
|
|
117
117
|
|
|
118
118
|
# used internally to ensure node api is set before using.
|
|
119
119
|
def node_api_
|
|
120
|
-
Aspera.assert(!@node_api.nil
|
|
120
|
+
Aspera.assert(!@node_api.nil?, 'Before using this object, set the node_api attribute to a Aspera::Rest object')
|
|
121
121
|
return @node_api
|
|
122
122
|
end
|
|
123
123
|
end
|
data/lib/aspera/api/aoc.rb
CHANGED
|
@@ -113,8 +113,10 @@ module Aspera
|
|
|
113
113
|
return client_key, DataRepository.instance.item(client_key)
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
-
#
|
|
117
|
-
|
|
116
|
+
# Base API url depends on domain, which could be "qa.xxx" or self-managed domain
|
|
117
|
+
# @param api_domain [String] the AoC domain (e.g. "ibmaspera.com" (SAAS_DOMAIN_PROD) or a self-managed domain)
|
|
118
|
+
# @return [String] the base URL for the AoC API
|
|
119
|
+
def api_base_url(api_domain)
|
|
118
120
|
return "https://api.#{api_domain}"
|
|
119
121
|
end
|
|
120
122
|
|
|
@@ -197,7 +199,7 @@ module Aspera
|
|
|
197
199
|
# @option return [Integer] :total The total number of items
|
|
198
200
|
def call_paging(query: {})
|
|
199
201
|
Aspera.assert_type(query, Hash){'query'}
|
|
200
|
-
Aspera.assert(block_given
|
|
202
|
+
Aspera.assert(block_given?, 'block required for call_paging')
|
|
201
203
|
# set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
|
|
202
204
|
query['per_page'] = 1000 unless query.key?('per_page')
|
|
203
205
|
max_items = query.delete(RestList::MAX_ITEMS)
|
|
@@ -211,7 +213,7 @@ module Aspera
|
|
|
211
213
|
new_query = query.clone
|
|
212
214
|
new_query['page'] = current_page
|
|
213
215
|
result_data, result_http = yield(new_query)
|
|
214
|
-
Aspera.assert(result_http)
|
|
216
|
+
Aspera.assert(result_http, 'expected HTTP result from paging block')
|
|
215
217
|
total_count = result_http[HEADER_X_TOTAL_COUNT]&.to_i
|
|
216
218
|
page_count += 1
|
|
217
219
|
current_page += 1
|
|
@@ -267,11 +269,12 @@ module Aspera
|
|
|
267
269
|
attr_accessor :ws_ids
|
|
268
270
|
|
|
269
271
|
# By default: no workspace
|
|
272
|
+
# @param
|
|
270
273
|
def initialize(
|
|
271
274
|
scope: nil,
|
|
272
275
|
subpath: API_V1,
|
|
273
276
|
secret_finder: nil,
|
|
274
|
-
# below: OAuth::AUTH_OPTIONS
|
|
277
|
+
# parameters below: OAuth::AUTH_OPTIONS
|
|
275
278
|
url:,
|
|
276
279
|
auth:,
|
|
277
280
|
client_id: nil,
|
|
@@ -284,7 +287,14 @@ module Aspera
|
|
|
284
287
|
)
|
|
285
288
|
# Test here because link may set url
|
|
286
289
|
Aspera.assert(url, 'Missing mandatory option: url', type: ParameterError)
|
|
287
|
-
|
|
290
|
+
# analyze type of url
|
|
291
|
+
url_info = self.class.link_info(url)
|
|
292
|
+
Log.dump(:url_info, url_info)
|
|
293
|
+
@private_link = url_info[:private_link]
|
|
294
|
+
Aspera.assert(auth, 'Missing mandatory option: auth', type: ParameterError) unless url_info.key?(:token)
|
|
295
|
+
# this is the base API url
|
|
296
|
+
api_url_base = self.class.api_base_url(url_info[:instance_domain])
|
|
297
|
+
Aspera.assert(scope, 'Missing mandatory option: scope', type: ParameterError) unless auth.eql?(:none)
|
|
288
298
|
# default values for client id
|
|
289
299
|
client_id, client_secret = self.class.get_client_info if client_id.nil?
|
|
290
300
|
# access key secrets are provided out of band to get node api access
|
|
@@ -298,28 +308,21 @@ module Aspera
|
|
|
298
308
|
# Used only for init: provided by user
|
|
299
309
|
@ws_ids = {id: nil, name: nil}
|
|
300
310
|
@home_info = nil
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
311
|
+
base_args = {
|
|
312
|
+
base_url: "#{api_url_base}/#{subpath}",
|
|
313
|
+
auth: {
|
|
314
|
+
type: :oauth2,
|
|
315
|
+
grant_method: url_info.key?(:token) ? :url_json : auth,
|
|
316
|
+
base_url: "#{api_url_base}/#{OAUTH_API_SUBPATH}/#{url_info[:organization]}",
|
|
317
|
+
params: {
|
|
318
|
+
client_id: client_id,
|
|
319
|
+
client_secret: client_secret,
|
|
320
|
+
scope: scope
|
|
321
|
+
}
|
|
307
322
|
}
|
|
308
323
|
}
|
|
309
|
-
#
|
|
310
|
-
|
|
311
|
-
Log.dump(:url_info, url_info)
|
|
312
|
-
@private_link = url_info[:private_link]
|
|
313
|
-
auth_params[:grant_method] = if url_info.key?(:token)
|
|
314
|
-
:url_json
|
|
315
|
-
else
|
|
316
|
-
Aspera.assert(auth, 'Missing mandatory option: auth', type: ParameterError)
|
|
317
|
-
auth
|
|
318
|
-
end
|
|
319
|
-
# this is the base API url
|
|
320
|
-
api_url_base = self.class.api_base_url(api_domain: url_info[:instance_domain])
|
|
321
|
-
# auth URL
|
|
322
|
-
auth_params[:base_url] = "#{api_url_base}/#{OAUTH_API_SUBPATH}/#{url_info[:organization]}"
|
|
324
|
+
# shortcut alias
|
|
325
|
+
auth_params = base_args[:auth]
|
|
323
326
|
# fill other auth parameters based on OAuth method
|
|
324
327
|
case auth_params[:grant_method]
|
|
325
328
|
when :web
|
|
@@ -344,12 +347,16 @@ module Aspera
|
|
|
344
347
|
auth_params[:json][:password] = password unless password.nil?
|
|
345
348
|
# basic auth required for /token
|
|
346
349
|
auth_params[:auth] = {type: :basic, username: client_id, password: client_secret}
|
|
347
|
-
|
|
350
|
+
when :boot
|
|
351
|
+
# cookie is optional: if absent, existing cache is used
|
|
352
|
+
auth_params[:cookie] = password unless password.nil?
|
|
353
|
+
auth_params[:username] = username unless username.nil?
|
|
354
|
+
when :none
|
|
355
|
+
auth_params.clear
|
|
356
|
+
auth_params[:type] = :none
|
|
357
|
+
else Aspera.error_unexpected_value(auth_params[:grant_method]){'auth, use one of: web, jwt, boot'}
|
|
348
358
|
end
|
|
349
|
-
super(
|
|
350
|
-
base_url: "#{api_url_base}/#{subpath}",
|
|
351
|
-
auth: auth_params
|
|
352
|
-
)
|
|
359
|
+
super(**base_args)
|
|
353
360
|
end
|
|
354
361
|
|
|
355
362
|
# Read using the query and paging
|
|
@@ -483,7 +490,7 @@ module Aspera
|
|
|
483
490
|
ak_secret = @secret_finder&.lookup_secret(url: node_info['url'], username: node_info['access_key'])
|
|
484
491
|
# If secret is available, or no scope, use basic auth
|
|
485
492
|
if scope.nil? || ak_secret
|
|
486
|
-
Aspera.assert(ak_secret, "Secret not found for access key #{node_info['access_key']}@#{node_info['url']}"
|
|
493
|
+
Aspera.assert(ak_secret, type: Error){"Secret not found for access key #{node_info['access_key']}@#{node_info['url']}"}
|
|
487
494
|
node_params[:auth] = {
|
|
488
495
|
type: :basic,
|
|
489
496
|
username: node_info['access_key'],
|
|
@@ -520,10 +527,10 @@ module Aspera
|
|
|
520
527
|
Log.dump(:metadata, pkg_meta)
|
|
521
528
|
pkg_meta.each do |field|
|
|
522
529
|
Aspera.assert_type(field, Hash){'metadata field'}
|
|
523
|
-
Aspera.assert(field.key?('name')
|
|
524
|
-
Aspera.assert(field.key?('values')
|
|
530
|
+
Aspera.assert(field.key?('name'), 'metadata field must have name')
|
|
531
|
+
Aspera.assert(field.key?('values'), 'metadata field must have values')
|
|
525
532
|
Aspera.assert_type(field['values'], Array){'metadata field values'}
|
|
526
|
-
Aspera.assert(
|
|
533
|
+
Aspera.assert(meta_schema.any?{ |i| i['name'].eql?(field['name'])}){"unknown metadata field: #{field['name']}"}
|
|
527
534
|
end
|
|
528
535
|
meta_schema.each do |field|
|
|
529
536
|
provided = pkg_meta.select{ |i| i['name'].eql?(field['name'])}
|
|
@@ -749,7 +756,7 @@ module Aspera
|
|
|
749
756
|
# @param types [Array] event types
|
|
750
757
|
def permissions_send_event(event_data:, app_info:, types: PERMISSIONS_CREATED)
|
|
751
758
|
Aspera.assert_type(types, Array)
|
|
752
|
-
Aspera.assert(!types.empty
|
|
759
|
+
Aspera.assert(!types.empty?, 'types must not be empty')
|
|
753
760
|
event_creation = {
|
|
754
761
|
'types' => types,
|
|
755
762
|
'node_id' => app_info.node_info['id'],
|
data/lib/aspera/api/cos_node.rb
CHANGED
|
@@ -63,7 +63,7 @@ module Aspera
|
|
|
63
63
|
ats_info = XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
|
|
64
64
|
Log.dump(:ats_info, ats_info)
|
|
65
65
|
Aspera.assert_hash_all(ats_info, String, nil){'ats_info'}
|
|
66
|
-
Aspera.assert((FASP_INFO_KEYS - ats_info.keys).empty
|
|
66
|
+
Aspera.assert((FASP_INFO_KEYS - ats_info.keys).empty?, 'ats_info missing required keys')
|
|
67
67
|
Aspera.assert_hash_all(ats_info['AccessKey'], String, String){'ats_info'}
|
|
68
68
|
@storage_credentials = {
|
|
69
69
|
'type' => 'token',
|
data/lib/aspera/api/faspex.rb
CHANGED
|
@@ -45,7 +45,7 @@ module Aspera
|
|
|
45
45
|
info = Rest.query_to_h(URI.parse(http['Location']).query)
|
|
46
46
|
Log.dump(:info, info)
|
|
47
47
|
raise Error, info['action_message'] if info['action_message']
|
|
48
|
-
Aspera.assert(info['code']
|
|
48
|
+
Aspera.assert(info['code'], 'Missing code in answer')
|
|
49
49
|
# Exchange code for token
|
|
50
50
|
return create_token_call(base_params.merge(
|
|
51
51
|
grant_type: 'authorization_code',
|
|
@@ -87,6 +87,7 @@ module Aspera
|
|
|
87
87
|
email_notifications
|
|
88
88
|
alternate_addresses
|
|
89
89
|
webhooks
|
|
90
|
+
file_processing
|
|
90
91
|
].freeze
|
|
91
92
|
# states for jobs not in final state
|
|
92
93
|
JOB_RUNNING = %w[queued working].freeze
|
|
@@ -193,15 +194,15 @@ module Aspera
|
|
|
193
194
|
}
|
|
194
195
|
# old: headers: {'Passcode' => @pub_link_context['passcode']}
|
|
195
196
|
when :boot
|
|
196
|
-
Aspera.assert(password, type: ParameterError)
|
|
197
|
+
Aspera.assert(password, 'Missing password', type: ParameterError)
|
|
197
198
|
# the password here is the token copied directly from browser in developer mode
|
|
198
199
|
{
|
|
199
200
|
base_url: "#{url}/#{root}",
|
|
200
201
|
headers: {'Authorization' => password}
|
|
201
202
|
}
|
|
202
203
|
when :web
|
|
203
|
-
Aspera.assert(client_id, type: ParameterError)
|
|
204
|
-
Aspera.assert(redirect_uri, type: ParameterError)
|
|
204
|
+
Aspera.assert(client_id, 'Missing client_id', type: ParameterError)
|
|
205
|
+
Aspera.assert(redirect_uri, 'Missing redirect_uri', type: ParameterError)
|
|
205
206
|
# opens a browser and ask user to auth using web
|
|
206
207
|
{
|
|
207
208
|
base_url: "#{url}/#{root}",
|
|
@@ -216,8 +217,8 @@ module Aspera
|
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
219
|
when :jwt
|
|
219
|
-
Aspera.assert(client_id, type: ParameterError)
|
|
220
|
-
Aspera.assert(private_key, type: ParameterError)
|
|
220
|
+
Aspera.assert(client_id, 'Missing client_id', type: ParameterError)
|
|
221
|
+
Aspera.assert(private_key, 'Missing private_key', type: ParameterError)
|
|
221
222
|
{
|
|
222
223
|
base_url: "#{url}/#{root}",
|
|
223
224
|
auth: {
|
data/lib/aspera/api/node.rb
CHANGED
|
@@ -174,9 +174,9 @@ module Aspera
|
|
|
174
174
|
# @param private_key [OpenSSL::PKey::RSA] Private key to sign the token
|
|
175
175
|
def bearer_token(access_key:, payload:, private_key:)
|
|
176
176
|
Aspera.assert_type(payload, Hash)
|
|
177
|
-
Aspera.assert(payload.key?('user_id'))
|
|
177
|
+
Aspera.assert(payload.key?('user_id'), 'payload must have user_id')
|
|
178
178
|
Aspera.assert_type(payload['user_id'], String)
|
|
179
|
-
Aspera.assert(!payload['user_id'].empty
|
|
179
|
+
Aspera.assert(!payload['user_id'].empty?, 'user_id must not be empty')
|
|
180
180
|
Aspera.assert_type(private_key, OpenSSL::PKey::RSA)
|
|
181
181
|
# Manage convenience parameters
|
|
182
182
|
expiration_sec = payload['_validity'] || BEARER_TOKEN_VALIDITY_DEFAULT
|
|
@@ -205,7 +205,7 @@ module Aspera
|
|
|
205
205
|
# If username is not provided, use the access key from the token
|
|
206
206
|
if access_key.nil?
|
|
207
207
|
access_key = Node.decode_scope(Node.decode_bearer_token(OAuth::Factory.bearer_token(bearer_auth))['scope'])[:access_key]
|
|
208
|
-
Aspera.assert(!access_key.nil
|
|
208
|
+
Aspera.assert(!access_key.nil?, 'access_key could not be determined from token')
|
|
209
209
|
end
|
|
210
210
|
return {
|
|
211
211
|
HEADER_X_ASPERA_ACCESS_KEY => access_key,
|
|
@@ -337,7 +337,7 @@ module Aspera
|
|
|
337
337
|
# @param top_file_path [String] path of top folder (default = /)
|
|
338
338
|
# @para query [Hash, nil] optional query for `read`
|
|
339
339
|
def process_folder_tree(method_sym:, state:, top_file_id:, top_file_path: '/', query: nil)
|
|
340
|
-
Aspera.assert(!top_file_path.nil
|
|
340
|
+
Aspera.assert(!top_file_path.nil?, 'top_file_path not set')
|
|
341
341
|
Log.log.debug{"process_folder_tree: node=#{@app_info ? @app_info.node_info['id'] : 'nil'}, file id=#{top_file_id}, path=#{top_file_path}"}
|
|
342
342
|
# Start at top folder
|
|
343
343
|
folders_to_explore = [{id: top_file_id, path: top_file_path}]
|
|
@@ -405,7 +405,7 @@ module Aspera
|
|
|
405
405
|
# - 'destination' [String]: Destination path (optional)
|
|
406
406
|
def resolve_api_fid_paths(top_file_id, paths)
|
|
407
407
|
Aspera.assert_type(paths, Array)
|
|
408
|
-
Aspera.assert(paths.size.positive
|
|
408
|
+
Aspera.assert(paths.size.positive?, 'paths must not be empty')
|
|
409
409
|
split_sources = paths.map{ |p| Pathname(p['source']).each_filename.to_a}
|
|
410
410
|
root = []
|
|
411
411
|
split_sources.map(&:size).min.times do |i|
|
|
@@ -490,7 +490,7 @@ module Aspera
|
|
|
490
490
|
case auth_params[:type]
|
|
491
491
|
when :basic
|
|
492
492
|
ak_name = auth_params[:username]
|
|
493
|
-
Aspera.assert(auth_params[:password]
|
|
493
|
+
Aspera.assert(auth_params[:password], 'no secret in node object')
|
|
494
494
|
ak_token = Rest.basic_authorization(auth_params[:username], auth_params[:password])
|
|
495
495
|
when :oauth2
|
|
496
496
|
ak_name = params[:headers][HEADER_X_ASPERA_ACCESS_KEY]
|
|
@@ -551,7 +551,7 @@ module Aspera
|
|
|
551
551
|
def read_with_paging(subpath, query = nil, iteration: nil, **call_args)
|
|
552
552
|
Aspera.assert_type(iteration, Array, NilClass){'iteration'}
|
|
553
553
|
Aspera.assert_type(query, Hash, NilClass){'query'}
|
|
554
|
-
Aspera.assert(!call_args.key?(:query))
|
|
554
|
+
Aspera.assert(!call_args.key?(:query), ':query must not be in call_args (use query parameter)')
|
|
555
555
|
query = {} if query.nil?
|
|
556
556
|
query[:iteration_token] = iteration[0] unless iteration.nil? || iteration[0].nil?
|
|
557
557
|
max = query.delete(RestList::MAX_ITEMS)
|
data/lib/aspera/ascmd.rb
CHANGED
|
@@ -129,10 +129,10 @@ module Aspera
|
|
|
129
129
|
Log.log.trace1{"execute_single:#{stdin_input}"}
|
|
130
130
|
# execute, get binary output
|
|
131
131
|
byte_buffer = @command_executor.execute(remote_cmd, input: stdin_input).unpack('C*')
|
|
132
|
-
Aspera.assert(!byte_buffer.empty
|
|
132
|
+
Aspera.assert(!byte_buffer.empty?, 'empty answer from server')
|
|
133
133
|
# get hash or table result
|
|
134
134
|
result = self.class.parse(byte_buffer, :result)
|
|
135
|
-
Aspera.assert(byte_buffer.empty
|
|
135
|
+
Aspera.assert(byte_buffer.empty?, 'unparsed bytes remaining')
|
|
136
136
|
# get and delete info,always present in results
|
|
137
137
|
system_info = result[:info]
|
|
138
138
|
result.delete(:info)
|
|
@@ -187,7 +187,7 @@ module Aspera
|
|
|
187
187
|
case type_descr[:decode]
|
|
188
188
|
when :base
|
|
189
189
|
num_bytes = type_name.eql?(:zstr) ? buffer.length : type_descr[:size]
|
|
190
|
-
Aspera.assert(buffer.length >= num_bytes
|
|
190
|
+
Aspera.assert(buffer.length >= num_bytes, 'not enough bytes')
|
|
191
191
|
byte_array = buffer.shift(num_bytes)
|
|
192
192
|
byte_array = [byte_array] unless byte_array.is_a?(Array)
|
|
193
193
|
result = byte_array.pack('C*').unpack1(type_descr[:unpack])
|
|
@@ -200,7 +200,7 @@ module Aspera
|
|
|
200
200
|
until buffer.empty?
|
|
201
201
|
btype = parse(buffer, :int8, indent_level)
|
|
202
202
|
length = parse(buffer, :int32, indent_level)
|
|
203
|
-
Aspera.assert(buffer.length >= length
|
|
203
|
+
Aspera.assert(buffer.length >= length, 'not enough bytes')
|
|
204
204
|
value = buffer.shift(length)
|
|
205
205
|
result.push({btype: btype, buffer: value})
|
|
206
206
|
Log.log.trace1{"#{' .' * indent_level}:buffer_list[#{result.length - 1}] #{result.last}"}
|
|
@@ -27,6 +27,10 @@ module Aspera
|
|
|
27
27
|
# It is used by object : AgentDirect to find necessary resources
|
|
28
28
|
# By default it takes the first Aspera product found
|
|
29
29
|
# The user can specify `ascp` location by calling: `sdk_folder=` method
|
|
30
|
+
#
|
|
31
|
+
# @!method self.instance
|
|
32
|
+
# Returns the singleton instance of Installation
|
|
33
|
+
# @return [Installation] the singleton instance
|
|
30
34
|
class Installation
|
|
31
35
|
include Singleton
|
|
32
36
|
|
|
@@ -57,7 +61,7 @@ module Aspera
|
|
|
57
61
|
# - "product:FIRST" to use ascp from first found product
|
|
58
62
|
def sdk_folder=(ascp_location)
|
|
59
63
|
Aspera.assert_type(ascp_location, String){'ascp_location'}
|
|
60
|
-
Aspera.assert(!ascp_location.empty
|
|
64
|
+
Aspera.assert(!ascp_location.empty?, 'ascp location cannot be empty: check your config file')
|
|
61
65
|
folder =
|
|
62
66
|
if ascp_location.start_with?(USE_PRODUCT_PREFIX)
|
|
63
67
|
product_name = ascp_location.delete_prefix(USE_PRODUCT_PREFIX)
|
|
@@ -247,7 +251,7 @@ module Aspera
|
|
|
247
251
|
# @yieldparam entry_stream [IO, Gem::Package::TarReader::Entry] Data stream
|
|
248
252
|
# @yieldparam link_target [String, nil] Link target if symlink, nil otherwise
|
|
249
253
|
def extract_archive_files(sdk_archive_path)
|
|
250
|
-
Aspera.assert(block_given
|
|
254
|
+
Aspera.assert(block_given?, 'missing block')
|
|
251
255
|
case sdk_archive_path
|
|
252
256
|
# Windows and Mac use zip
|
|
253
257
|
when /\.zip$/
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'aspera/assert'
|
|
4
|
+
|
|
5
|
+
module Aspera
|
|
6
|
+
module Cli
|
|
7
|
+
# Global objects shared with plugins
|
|
8
|
+
class Context
|
|
9
|
+
# @type [Array<Symbol>]
|
|
10
|
+
MEMBERS = %i[options transfer config formatter persistency man_header presets http_config].freeze
|
|
11
|
+
# @!attribute [rw] options
|
|
12
|
+
# @return [Manager] the command line options manager
|
|
13
|
+
# @!attribute [rw] transfer
|
|
14
|
+
# @return [TransferAgent] the transfer agent, used by transfer plugins
|
|
15
|
+
# @!attribute [rw] config
|
|
16
|
+
# @return [Plugins::Config] the configuration plugin, used by plugins to get configuration values and presets
|
|
17
|
+
# @!attribute [rw] formatter
|
|
18
|
+
# @return [Formatter] the formatter, used by plugins to display results and messages
|
|
19
|
+
# @!attribute [rw] persistency
|
|
20
|
+
# @return [Object] # whatever the type is
|
|
21
|
+
# @!attribute [rw] man_header
|
|
22
|
+
# @return [Boolean] whether to display the manual header in plugin help
|
|
23
|
+
# @!attribute [rw] presets
|
|
24
|
+
# @return [PresetManager] manages the YAML config file and preset resolution
|
|
25
|
+
# @!attribute [rw] http_config
|
|
26
|
+
# @return [Http] manages HTTP/S and TLS runtime options
|
|
27
|
+
attr_accessor(*MEMBERS)
|
|
28
|
+
|
|
29
|
+
# Initialize all members to nil, so that they are defined and can be validated later
|
|
30
|
+
# @return [nil]
|
|
31
|
+
def initialize
|
|
32
|
+
MEMBERS.each{ |i| instance_variable_set(:"@#{i}", nil)}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Validate that all members are set, raise exception if not
|
|
36
|
+
# @raise [Aspera::AssertionError] if any member is not set
|
|
37
|
+
# @return [nil]
|
|
38
|
+
def validate
|
|
39
|
+
MEMBERS.each do |i|
|
|
40
|
+
Aspera.assert(instance_variable_defined?(:"@#{i}")){"context member @#{i} is not defined"}
|
|
41
|
+
Aspera.assert(!instance_variable_get(:"@#{i}").nil?){"context member @#{i} is nil"}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Check if the context is in manual-only mode
|
|
46
|
+
# @return [Boolean] true if in manual-only mode
|
|
47
|
+
def only_manual?
|
|
48
|
+
transfer.eql?(:only_manual)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Set the context to manual-only mode
|
|
52
|
+
# @return [Symbol] :only_manual
|
|
53
|
+
def only_manual!
|
|
54
|
+
@transfer = :only_manual
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -86,6 +86,7 @@ module Aspera
|
|
|
86
86
|
# Base handlers
|
|
87
87
|
# Other handlers can be set using `on`
|
|
88
88
|
# e.g. `preset` is reader in config plugin
|
|
89
|
+
# @type [Hash{Symbol => Proc}]
|
|
89
90
|
@handlers = {
|
|
90
91
|
val: lambda{ |i| i},
|
|
91
92
|
base64: lambda{ |i| Base64.decode64(i)},
|
|
@@ -100,7 +101,7 @@ module Aspera
|
|
|
100
101
|
path: lambda{ |i| File.expand_path(i)},
|
|
101
102
|
re: lambda{ |i| Regexp.new(i, Regexp::MULTILINE)},
|
|
102
103
|
ruby: lambda{ |i| Environment.secure_eval(i, __FILE__, __LINE__)},
|
|
103
|
-
s: lambda
|
|
104
|
+
s: lambda(&:to_s),
|
|
104
105
|
secret: lambda{ |i| prompt = i.empty? ? 'secret' : i; $stdin.getpass("#{prompt}> ")}, # rubocop:disable Style/Semicolon
|
|
105
106
|
stdin: lambda{ |i| ExtendedValue.read_stdin(i)},
|
|
106
107
|
yaml: lambda{ |i| YAML.load(i)},
|
|
@@ -137,7 +138,7 @@ module Aspera
|
|
|
137
138
|
# Add a new handler
|
|
138
139
|
def on(name, &block)
|
|
139
140
|
Aspera.assert_type(name, Symbol){'name'}
|
|
140
|
-
Aspera.assert(block)
|
|
141
|
+
Aspera.assert(block){"block required when registering handler for #{name}"}
|
|
141
142
|
Log.log.debug{"Setting handler for #{name}"}
|
|
142
143
|
@handlers[name] = block
|
|
143
144
|
update_regex
|