aspera-cli 4.26.0 → 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 +36 -4
- 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 +45 -37
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/faspex.rb +7 -6
- data/lib/aspera/api/node.rb +9 -9
- data/lib/aspera/ascmd.rb +4 -4
- data/lib/aspera/ascp/installation.rb +13 -6
- data/lib/aspera/assert.rb +17 -13
- data/lib/aspera/cli/context.rb +58 -0
- data/lib/aspera/cli/extended_value.rb +9 -4
- data/lib/aspera/cli/formatter.rb +91 -187
- data/lib/aspera/cli/http.rb +167 -0
- data/lib/aspera/cli/manager.rb +132 -77
- data/lib/aspera/cli/options.schema.yaml +82 -0
- data/lib/aspera/cli/plugins/alee.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +113 -77
- data/lib/aspera/cli/plugins/ats.rb +16 -16
- data/lib/aspera/cli/plugins/base.rb +64 -49
- data/lib/aspera/cli/plugins/config.rb +172 -444
- 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 +22 -22
- data/lib/aspera/cli/plugins/faspex5.rb +68 -49
- 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 +80 -80
- 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} +48 -130
- data/lib/aspera/cli/sync_actions.rb +15 -11
- data/lib/aspera/cli/terminal_formatter.rb +65 -0
- data/lib/aspera/cli/transfer_agent.rb +17 -15
- 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 +22 -18
- data/lib/aspera/data_repository.rb +4 -0
- data/lib/aspera/dot_container.rb +1 -1
- data/lib/aspera/environment.rb +25 -6
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/formatter_interface.rb +14 -0
- data/lib/aspera/hash_ext.rb +6 -0
- 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 +10 -5
- data/lib/aspera/markdown.rb +4 -1
- 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 +38 -14
- 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 +6 -3
- data/lib/aspera/rest.rb +9 -5
- 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 +62811 -0
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +9637 -0
- data/lib/aspera/schema/async_tables.yaml +361 -0
- data/lib/aspera/schema/documentation.rb +107 -0
- data/lib/aspera/schema/reader.rb +75 -0
- data/lib/aspera/schema/registry.rb +70 -0
- data/lib/aspera/secret_hider.rb +4 -0
- data/lib/aspera/sync/conf.schema.yaml +0 -26
- data/lib/aspera/sync/database.rb +14 -10
- data/lib/aspera/sync/operations.rb +14 -10
- data/lib/aspera/temp_file_manager.rb +4 -0
- data/lib/aspera/transfer/faux_file.rb +1 -1
- data/lib/aspera/transfer/parameters.rb +4 -4
- data/lib/aspera/transfer/resumer.rb +2 -2
- data/lib/aspera/transfer/spec.rb +3 -3
- data/lib/aspera/transfer/spec.schema.yaml +18 -9
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +1 -1
- data/lib/aspera/yaml.rb +4 -2
- data.tar.gz.sig +0 -0
- metadata +28 -15
- metadata.gz.sig +1 -1
- data/lib/aspera/transfer/spec_doc.rb +0 -76
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,38 @@
|
|
|
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`.
|
|
22
|
+
|
|
23
|
+
## 4.26.1
|
|
24
|
+
|
|
25
|
+
Released: 2026-06-11
|
|
26
|
+
|
|
27
|
+
### New Features
|
|
28
|
+
|
|
29
|
+
* `aoc`: Added new command `admin workspace shared_folder <workspace ID> node <shared folder ID>` to provide direct access to node operations from shared folders.
|
|
30
|
+
* **global**: Schema for Extended Value for option or command argument can now be retrieved using the special value `help` (e.g., `--ts=help` or `package send help`). Those are generated from JSON schema descriptions.
|
|
31
|
+
* **doc**: Some tables in documentation are now generated from JSON schema descriptions.
|
|
32
|
+
|
|
33
|
+
### Issues Fixed
|
|
34
|
+
|
|
35
|
+
* **global**: Resolved issue where supported enumerated values were not properly listed when no value was provided (e.g., for command parameters).
|
|
4
36
|
|
|
5
37
|
## 4.26.0
|
|
6
38
|
|
|
@@ -17,7 +49,7 @@ Released: 2026-05-28
|
|
|
17
49
|
* `aoc`: Support selection of workspace using percent selectors: `%name:` and `%id:`.
|
|
18
50
|
* **global**: Added download URLs for `transferd` 1.1.8.
|
|
19
51
|
* **global**: New Extended Value modifier: `s` converts to `String`.
|
|
20
|
-
* **global**: Parameter `str_lst_sep`
|
|
52
|
+
* **global**: Parameter `str_lst_sep` of option `table_style` allows setting separator for list of strings.
|
|
21
53
|
|
|
22
54
|
### Issues Fixed
|
|
23
55
|
|
|
@@ -57,7 +89,7 @@ Released: 2026-03-04
|
|
|
57
89
|
|
|
58
90
|
### New Features
|
|
59
91
|
|
|
60
|
-
* **
|
|
92
|
+
* **global**: If `@:` is used, then marker `END` optionally marks the end of collected arguments.
|
|
61
93
|
* `format`: `display` defaults to `info` only if `format` is set to `table`, else defaults to `data`.
|
|
62
94
|
* `node`: Parameter `accept_v4` of option `node_api` (boolean, defaults to `true`) allows using gen4 browsing with `Accept-Version: 4.0` for best performance when there are thousands of files.
|
|
63
95
|
|
|
@@ -440,7 +472,7 @@ Released: 2024-07-13
|
|
|
440
472
|
|
|
441
473
|
### Breaking Changes
|
|
442
474
|
|
|
443
|
-
* `config`: Command `remote_certificate` now takes a
|
|
475
|
+
* `config`: Command `remote_certificate` now takes a command.
|
|
444
476
|
* **global**: Moved a few internal classes in new/renamed modules.
|
|
445
477
|
* **global**: Deprecated pseudo transfer specification parameters starting with `EX_`:
|
|
446
478
|
* `EX_ssh_key_paths`: Use spec `ssh_private_key` or option `transfer_info={"ascp_args":["-i","..."]}`
|
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
|
|
@@ -362,6 +369,7 @@ module Aspera
|
|
|
362
369
|
end
|
|
363
370
|
end
|
|
364
371
|
|
|
372
|
+
# @param expected [Array<String>] Link types
|
|
365
373
|
def assert_public_link_types(expected)
|
|
366
374
|
Aspera.assert_values(public_link['purpose'], expected){'public link type'}
|
|
367
375
|
end
|
|
@@ -482,7 +490,7 @@ module Aspera
|
|
|
482
490
|
ak_secret = @secret_finder&.lookup_secret(url: node_info['url'], username: node_info['access_key'])
|
|
483
491
|
# If secret is available, or no scope, use basic auth
|
|
484
492
|
if scope.nil? || ak_secret
|
|
485
|
-
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']}"}
|
|
486
494
|
node_params[:auth] = {
|
|
487
495
|
type: :basic,
|
|
488
496
|
username: node_info['access_key'],
|
|
@@ -519,10 +527,10 @@ module Aspera
|
|
|
519
527
|
Log.dump(:metadata, pkg_meta)
|
|
520
528
|
pkg_meta.each do |field|
|
|
521
529
|
Aspera.assert_type(field, Hash){'metadata field'}
|
|
522
|
-
Aspera.assert(field.key?('name')
|
|
523
|
-
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')
|
|
524
532
|
Aspera.assert_type(field['values'], Array){'metadata field values'}
|
|
525
|
-
Aspera.assert(
|
|
533
|
+
Aspera.assert(meta_schema.any?{ |i| i['name'].eql?(field['name'])}){"unknown metadata field: #{field['name']}"}
|
|
526
534
|
end
|
|
527
535
|
meta_schema.each do |field|
|
|
528
536
|
provided = pkg_meta.select{ |i| i['name'].eql?(field['name'])}
|
|
@@ -557,7 +565,7 @@ module Aspera
|
|
|
557
565
|
full_recipient_info = lookup_with_q(entity_type, value: short_recipient_info, query: {'workspace_id' => ws_id})
|
|
558
566
|
rescue EntityNotFound
|
|
559
567
|
# dropboxes cannot be created on the fly
|
|
560
|
-
Aspera.assert_values(entity_type,
|
|
568
|
+
Aspera.assert_values(entity_type, %w[contacts], type: Error){"No such shared inbox in workspace #{ws_id}"}
|
|
561
569
|
# unknown user: create it as external user
|
|
562
570
|
full_recipient_info = create('contacts', {
|
|
563
571
|
'current_workspace_id' => ws_id,
|
|
@@ -748,7 +756,7 @@ module Aspera
|
|
|
748
756
|
# @param types [Array] event types
|
|
749
757
|
def permissions_send_event(event_data:, app_info:, types: PERMISSIONS_CREATED)
|
|
750
758
|
Aspera.assert_type(types, Array)
|
|
751
|
-
Aspera.assert(!types.empty
|
|
759
|
+
Aspera.assert(!types.empty?, 'types must not be empty')
|
|
752
760
|
event_creation = {
|
|
753
761
|
'types' => types,
|
|
754
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
|
@@ -165,7 +165,7 @@ module Aspera
|
|
|
165
165
|
items = scope.split(Scope::SEPARATOR, 2)
|
|
166
166
|
Aspera.assert(items.length.eql?(2)){"invalid scope: #{scope}"}
|
|
167
167
|
Aspera.assert(items[0].start_with?(Scope::NODE_PREFIX)){"invalid scope: #{scope}"}
|
|
168
|
-
return {access_key: items[0]
|
|
168
|
+
return {access_key: items[0].delete_prefix(Scope::NODE_PREFIX), scope: items[1]}
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
# Create an Aspera Node bearer token
|
|
@@ -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]
|
|
@@ -540,7 +540,7 @@ module Aspera
|
|
|
540
540
|
else
|
|
541
541
|
transfer_spec.merge!(transport_params)
|
|
542
542
|
end
|
|
543
|
-
Aspera.assert_values(transfer_spec['remote_user'], Transfer::Spec::ACCESS_KEY_TRANSFER_USER, type: :warn){'transfer user'}
|
|
543
|
+
Aspera.assert_values(transfer_spec['remote_user'], [Transfer::Spec::ACCESS_KEY_TRANSFER_USER], type: :warn){'transfer user'}
|
|
544
544
|
return transfer_spec
|
|
545
545
|
end
|
|
546
546
|
|
|
@@ -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,10 +61,10 @@ 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
|
-
product_name = ascp_location
|
|
67
|
+
product_name = ascp_location.delete_prefix(USE_PRODUCT_PREFIX)
|
|
64
68
|
if product_name.eql?(FIRST_FOUND)
|
|
65
69
|
pl = installed_products.first
|
|
66
70
|
raise "No Aspera transfer module or SDK found.\nRefer to the manual or install SDK with command:\nascli conf transferd install" if pl.nil?
|
|
@@ -113,7 +117,7 @@ module Aspera
|
|
|
113
117
|
file = File.join(File.dirname(file), Environment.instance.exe_file(k.to_s)) unless k.eql?(:transferd)
|
|
114
118
|
when :ssh_private_dsa, :ssh_private_rsa
|
|
115
119
|
# assume last 3 letters are type
|
|
116
|
-
type = k.to_s[-3
|
|
120
|
+
type = k.to_s[-3..].to_sym
|
|
117
121
|
file = check_or_create_sdk_file("aspera_bypass_#{type}.pem"){DataRepository.instance.item(type)}
|
|
118
122
|
when :aspera_license
|
|
119
123
|
file = check_or_create_sdk_file('aspera-license'){DataRepository.instance.item(:license)}
|
|
@@ -243,9 +247,11 @@ module Aspera
|
|
|
243
247
|
end
|
|
244
248
|
|
|
245
249
|
# @param sdk_archive_path [String] path to SDK archive
|
|
246
|
-
# @
|
|
250
|
+
# @yieldparam entry_name [String] File path in archive
|
|
251
|
+
# @yieldparam entry_stream [IO, Gem::Package::TarReader::Entry] Data stream
|
|
252
|
+
# @yieldparam link_target [String, nil] Link target if symlink, nil otherwise
|
|
247
253
|
def extract_archive_files(sdk_archive_path)
|
|
248
|
-
Aspera.assert(block_given
|
|
254
|
+
Aspera.assert(block_given?, 'missing block')
|
|
249
255
|
case sdk_archive_path
|
|
250
256
|
# Windows and Mac use zip
|
|
251
257
|
when /\.zip$/
|
|
@@ -281,7 +287,8 @@ module Aspera
|
|
|
281
287
|
# @param url [nil, String] URL to SDK archive, if nil: default url for version
|
|
282
288
|
# @param version [nil, String] Specific version, if nil: latest version
|
|
283
289
|
# @param backup [Boolean] If destination folder exists, then rename
|
|
284
|
-
# @
|
|
290
|
+
# @yieldparam entry_name [String] File path from archive
|
|
291
|
+
# @yieldreturn [String, nil] Destination sub folder (end with /) or file, or nil to not extract
|
|
285
292
|
# @return [Array] name, ascp version (from execution), folder
|
|
286
293
|
def install_sdk(folder:, url: nil, version: nil, backup: true)
|
|
287
294
|
url ||= sdk_url_for_platform(version: version)
|
data/lib/aspera/assert.rb
CHANGED
|
@@ -20,21 +20,24 @@ module Aspera
|
|
|
20
20
|
class << self
|
|
21
21
|
# Replaces `raise` in assertion
|
|
22
22
|
# Allows sending exception, or just error log, when type is `:error`
|
|
23
|
-
# @param type [Exception,Symbol] Send to log if symbol, else raise exception
|
|
23
|
+
# @param type [Exception, Symbol] Send to log if symbol, else raise exception
|
|
24
24
|
# @param message [String] Message for error.
|
|
25
|
+
# @raise [Exception]
|
|
26
|
+
# @return [nil]
|
|
25
27
|
def report_error(type, message)
|
|
26
28
|
if type.is_a?(Symbol)
|
|
27
29
|
Log.log.send(type, message)
|
|
28
30
|
else
|
|
29
31
|
raise type, message
|
|
30
32
|
end
|
|
33
|
+
nil
|
|
31
34
|
end
|
|
32
35
|
|
|
33
36
|
# Assert that a condition is true, else raise exception
|
|
34
37
|
# @param assertion [TrueClass, FalseClass] Must be true
|
|
35
|
-
# @param info [String,nil] Fixed message in case assert fails, else use
|
|
38
|
+
# @param info [String,nil] Fixed message in case assert fails, else use block
|
|
36
39
|
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
|
37
|
-
# @
|
|
40
|
+
# @yieldreturn [String] A string that describes the problem for complex messages
|
|
38
41
|
# The block is executed in the context of the Aspera module
|
|
39
42
|
def assert(assertion, info = nil, type: AssertError)
|
|
40
43
|
raise InternalError, 'bad assert: both info and block given' unless info.nil? || !block_given?
|
|
@@ -50,18 +53,18 @@ module Aspera
|
|
|
50
53
|
# @param value [Object] The value to check
|
|
51
54
|
# @param classes [Class, Array] The expected type(s)
|
|
52
55
|
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
|
53
|
-
# @
|
|
56
|
+
# @yieldreturn [String] Additional description to prepend to the error message
|
|
54
57
|
def assert_type(value, *classes, type: AssertError)
|
|
55
|
-
assert(classes.any?{ |k| value.is_a?(k)}, type: type){"#{"#{yield}: " if block_given?}expecting #{classes.join(', ')}, but have (#{value.class})#{value.inspect}"}
|
|
58
|
+
assert(classes.any?{ |k| value.is_a?(k)}, type: type){"#{"#{yield}: " if block_given?}expecting type #{classes.join(', ')}, but have (#{value.class})#{value.inspect}"}
|
|
56
59
|
end
|
|
57
60
|
|
|
58
61
|
# Assert that all value of array are of the same specified type.
|
|
59
62
|
# @param array [Array] The array to check
|
|
60
63
|
# @param klass [Class] The expected type of elements
|
|
61
64
|
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
|
62
|
-
# @
|
|
65
|
+
# @yieldreturn [String] Additional description to prepend to the error message
|
|
63
66
|
def assert_array_all(array, klass, type: AssertError)
|
|
64
|
-
assert_type(array, Array, type:
|
|
67
|
+
assert_type(array, Array, type: AssertError){'array'}
|
|
65
68
|
assert(array.all?(klass), type: type){"#{"#{yield}: " if block_given?}expecting all as #{klass}, but have #{array.map(&:class).uniq}"}
|
|
66
69
|
end
|
|
67
70
|
|
|
@@ -70,19 +73,20 @@ module Aspera
|
|
|
70
73
|
# @param key_class [Class] The expected type of keys (or nil)
|
|
71
74
|
# @param value_class [Class] The expected type of values (or nil)
|
|
72
75
|
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
|
73
|
-
# @
|
|
76
|
+
# @yieldreturn [String] Additional description to prepend to the error message
|
|
74
77
|
def assert_hash_all(hash, key_class, value_class, type: AssertError)
|
|
75
|
-
assert_type(hash, Hash, type:
|
|
76
|
-
assert_array_all(hash.keys, key_class, type:
|
|
77
|
-
assert_array_all(hash.values, value_class, type:
|
|
78
|
+
assert_type(hash, Hash, type: AssertError){'hash'}
|
|
79
|
+
assert_array_all(hash.keys, key_class, type: type){"#{"#{yield}: " if block_given?}keys"} unless key_class.nil?
|
|
80
|
+
assert_array_all(hash.values, value_class, type: type){"#{"#{yield}: " if block_given?}values"} unless value_class.nil?
|
|
78
81
|
end
|
|
79
82
|
|
|
80
83
|
# Assert that value is one of the given values
|
|
81
84
|
# @param value [Object] Value to check
|
|
82
85
|
# @param values [Array] Accepted values
|
|
83
86
|
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
|
84
|
-
# @
|
|
87
|
+
# @yieldreturn [String] Additional description to prepend to the error message
|
|
85
88
|
def assert_values(value, values, type: AssertError)
|
|
89
|
+
assert_type(values, Array, type: AssertError){'values'}
|
|
86
90
|
assert(values.include?(value), type: type) do
|
|
87
91
|
val_list = values.inspect
|
|
88
92
|
val_list = "one of #{val_list}" if values.is_a?(Array)
|
|
@@ -93,7 +97,7 @@ module Aspera
|
|
|
93
97
|
# The value is not one of the expected values
|
|
94
98
|
# @param value [Object] The wrong value
|
|
95
99
|
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
|
96
|
-
# @
|
|
100
|
+
# @yieldreturn [String] Additional description to prepend to the error message
|
|
97
101
|
def error_unexpected_value(value, type: InternalError)
|
|
98
102
|
report_error(type, "#{"#{yield}: " if block_given?}unexpected value: #{value.inspect}")
|
|
99
103
|
end
|