assinafy 1.5.0 → 1.5.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
- data/CHANGELOG.md +51 -4
- data/README.md +231 -11
- data/docs/API_REFERENCE.md +723 -0
- data/lib/assinafy/client.rb +51 -15
- data/lib/assinafy/configuration.rb +29 -5
- data/lib/assinafy/resources/account_resource.rb +15 -8
- data/lib/assinafy/resources/assignment_resource.rb +51 -13
- data/lib/assinafy/resources/auth_resource.rb +13 -11
- data/lib/assinafy/resources/base_resource.rb +120 -38
- data/lib/assinafy/resources/document_resource.rb +48 -46
- data/lib/assinafy/resources/field_resource.rb +38 -15
- data/lib/assinafy/resources/signer_document_resource.rb +39 -16
- data/lib/assinafy/resources/signer_resource.rb +84 -25
- data/lib/assinafy/resources/tag_resource.rb +1 -1
- data/lib/assinafy/resources/template_resource.rb +3 -0
- data/lib/assinafy/resources/user_resource.rb +10 -5
- data/lib/assinafy/resources/webhook_resource.rb +1 -1
- data/lib/assinafy/support/webhook_verifier.rb +4 -3
- data/lib/assinafy/version.rb +2 -1
- data/sig/assinafy.rbs +363 -0
- metadata +18 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 37dc8933996b9192a9f12896d772d4d5f745169fcaf0bb13b06cd199e4650bcd
|
|
4
|
+
data.tar.gz: 70fe0b92c876f387aeb3656f18b0e78d3cbc09d41dbefc73bba96bb6177b423b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5bd2d4cfc525e22c84d4de1cc232f4666b769bcdd66e21d56397ad1c4a61bc1c482a7a9b183dcadfde1bd098e624ada2776f847e2c55fcf65e43d20f89437d34
|
|
7
|
+
data.tar.gz: 4586c42fc917ef30c6e7eef7718310fd583ce2817acecdf2de5f3f972b405e8986c9a474aa5dbdd9f3c476b2651a700c641471c8154d710e85f2ba4c7c7ebbc1
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the `assinafy` Ruby gem are documented here.
|
|
4
4
|
|
|
5
|
+
## 1.5.2
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `base_url` must now be an absolute `http`/`https` URL with a host. Other schemes, scheme-less
|
|
10
|
+
hosts, and relative paths raise `Assinafy::ValidationError` at construction instead of sending
|
|
11
|
+
credentials to them or surfacing a raw `URI::InvalidURIError`.
|
|
12
|
+
- `AssignmentResource.build_payload` now rejects a non-String `message` or `expires_at` and a
|
|
13
|
+
`copy_receivers` value that is not an array of non-empty signer IDs, instead of forwarding them
|
|
14
|
+
to the API verbatim.
|
|
15
|
+
- `Client#upload_and_request_signatures` validates the whole assignment body before uploading, so
|
|
16
|
+
malformed `message`, `expires_at`, or `copy_receivers` values no longer leave an uploaded
|
|
17
|
+
document and freshly created signers behind.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Authentication and API-key operations route through the shared resource request helpers used by
|
|
22
|
+
every other resource.
|
|
23
|
+
|
|
24
|
+
## 1.5.1
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- A complete document workflow in the README and an API reference covering all 89 published
|
|
29
|
+
operations, five supported template operations, request bodies, success responses, errors,
|
|
30
|
+
and all 39 published schemas.
|
|
31
|
+
- A weekly upstream contract check and packaged-gem installation smoke test.
|
|
32
|
+
- Published RBS signatures and Steep verification in CI and release checks.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- Every client and resource request now sends the exact versioned
|
|
37
|
+
`Assinafy-Ruby-SDK/v1.5.1` User-Agent.
|
|
38
|
+
- Public and signer-authenticated operations no longer inherit workspace credentials.
|
|
39
|
+
- Collection and binary operations now reject malformed successful responses instead of
|
|
40
|
+
silently returning misleading values.
|
|
41
|
+
- Document and template uploads validate safe filenames, non-empty PDF content, and document
|
|
42
|
+
upload IDs before later writes.
|
|
43
|
+
- The high-level upload/signature workflow validates every signer before uploading and retains
|
|
44
|
+
created resource IDs in error context for explicit cleanup.
|
|
45
|
+
- Request validation now rejects malformed signer fields, assignment items, tag IDs, field
|
|
46
|
+
values, and signer-document identifiers before network calls.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- Development and release verification use Ruby 4.0.6 while CI retains Ruby 3.2 compatibility
|
|
51
|
+
and tests Ruby 3.3, 3.4, 4.0, and head.
|
|
52
|
+
|
|
5
53
|
## 1.5.0
|
|
6
54
|
|
|
7
55
|
### Added
|
|
@@ -53,9 +101,8 @@ All notable changes to the `assinafy` Ruby gem are documented here.
|
|
|
53
101
|
|
|
54
102
|
## 1.4.0
|
|
55
103
|
|
|
56
|
-
This release
|
|
57
|
-
|
|
58
|
-
at <https://api.assinafy.com.br/v1/docs>.
|
|
104
|
+
This release aligned the SDK with the live Assinafy v1 API and the published
|
|
105
|
+
documentation at <https://api.assinafy.com.br/v1/docs>.
|
|
59
106
|
|
|
60
107
|
### Added
|
|
61
108
|
|
|
@@ -92,7 +139,7 @@ at <https://api.assinafy.com.br/v1/docs>.
|
|
|
92
139
|
### Changed
|
|
93
140
|
|
|
94
141
|
- **Minimum Ruby is now 3.2** (3.0 and 3.1 are end-of-life). CI tests 3.2, 3.3, 3.4,
|
|
95
|
-
4.0, and head. `.ruby-version` is committed (3.4.8) and drives the lint
|
|
142
|
+
4.0, and head. `.ruby-version` is committed (3.4.8) and drives the lint, security, and release jobs.
|
|
96
143
|
- `SignerDocumentResource#list` accepts an optional `signer_access_code:` (the endpoint
|
|
97
144
|
also supports workspace `X-Api-Key` auth); the class auth documentation was corrected.
|
|
98
145
|
- CI gained a `concurrency` group to cancel superseded runs.
|
data/README.md
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
Ruby SDK for the [Assinafy API v1](https://api.assinafy.com.br/v1/docs).
|
|
7
7
|
|
|
8
|
-
The SDK
|
|
8
|
+
The SDK exposes every Assinafy API v1 operation and the complete supported template lifecycle. The checked-in [`spec/api_coverage_spec.rb`](spec/api_coverage_spec.rb) validates that each route maps uniquely to a public SDK method.
|
|
9
9
|
|
|
10
10
|
- **Source:** <https://github.com/assinafy/ruby-sdk>
|
|
11
11
|
- **Issues:** <https://github.com/assinafy/ruby-sdk/issues>
|
|
12
12
|
- **API docs:** <https://api.assinafy.com.br/v1/docs>
|
|
13
|
+
- **Ruby SDK API reference:** [`docs/API_REFERENCE.md`](docs/API_REFERENCE.md)
|
|
13
14
|
|
|
14
15
|
## Requirements
|
|
15
16
|
|
|
@@ -81,9 +82,14 @@ client = Assinafy::Client.new(
|
|
|
81
82
|
|
|
82
83
|
- `api_key:` sends `X-Api-Key` (preferred).
|
|
83
84
|
- `token:` sends `Authorization: Bearer ...` (legacy session token).
|
|
85
|
+
- Configure exactly one credential. If both are supplied, the SDK sends only `X-Api-Key`.
|
|
84
86
|
- A client can also be created with no credentials for authentication and public/signer endpoints.
|
|
87
|
+
- `base_url:` must be an absolute `http`/`https` URL. Anything else — a scheme-less host, a relative path, or
|
|
88
|
+
another scheme — raises `Assinafy::ValidationError` instead of attaching your credentials to it. A trailing
|
|
89
|
+
slash is stripped.
|
|
85
90
|
- Account-scoped methods document a per-call account override for multi-workspace tenants.
|
|
86
91
|
- Provide a `Logger`-compatible `logger:` to observe upload/assignment/webhook lifecycle messages.
|
|
92
|
+
- Requests send `User-Agent: Assinafy-Ruby-SDK/v<Assinafy::VERSION>`; the suffix always follows the gem version.
|
|
87
93
|
|
|
88
94
|
`Client.from_config(hash)` accepts string- or symbol-keyed hashes (e.g. parsed YAML).
|
|
89
95
|
|
|
@@ -145,9 +151,12 @@ client.users.notification_preferences # returns all nine owner-e
|
|
|
145
151
|
client.users.update_notification_preferences(SignerDeclined: false) # partial request; returns all nine
|
|
146
152
|
```
|
|
147
153
|
|
|
148
|
-
Both stats methods return rows with `period`, `documents_uploaded`, `documents_sent`,
|
|
149
|
-
`
|
|
150
|
-
`
|
|
154
|
+
Both stats methods return rows with `period`, `documents_uploaded`, `documents_sent`, `signature_requests`,
|
|
155
|
+
`signature_requests_notification_email`, `signature_requests_notification_whatsapp`,
|
|
156
|
+
`signature_requests_notification_bypass`, `signature_requests_verification_email`,
|
|
157
|
+
`signature_requests_verification_whatsapp`, `signature_requests_verification_bypass`,
|
|
158
|
+
`signature_requests_verification_digital_certificate`, `signature_requests_viewed`,
|
|
159
|
+
`signature_requests_completed`, and `documents_certified`.
|
|
151
160
|
|
|
152
161
|
### Documents
|
|
153
162
|
|
|
@@ -174,7 +183,7 @@ client.documents.send_token('document-id', email: 'alice@example.com') # current
|
|
|
174
183
|
client.documents.list_tags('document-id')
|
|
175
184
|
client.documents.replace_tags('document-id', ['tag-id-1', 'tag-id-2'])
|
|
176
185
|
client.documents.append_tags('document-id', ['tag-id-3'])
|
|
177
|
-
# The
|
|
186
|
+
# The deployed sandbox also accepts existing tag names in these arrays.
|
|
178
187
|
client.documents.detach_tag('document-id', 'tag-id')
|
|
179
188
|
|
|
180
189
|
# Template-driven creation
|
|
@@ -204,7 +213,7 @@ client.signers.list(search: 'alice', per_page: 50) # returns { data:, meta: }
|
|
|
204
213
|
client.signers.update('signer-id', full_name: 'Alice S.', government_id: '00000000000')
|
|
205
214
|
client.signers.delete('signer-id')
|
|
206
215
|
|
|
207
|
-
# Convenience: case-insensitive lookup
|
|
216
|
+
# Convenience: case-insensitive lookup; nil means a successful search found no match
|
|
208
217
|
client.signers.find_by_email('alice@example.com')
|
|
209
218
|
```
|
|
210
219
|
|
|
@@ -381,8 +390,205 @@ rescue Assinafy::ApiError => e
|
|
|
381
390
|
end
|
|
382
391
|
```
|
|
383
392
|
|
|
384
|
-
|
|
385
|
-
|
|
393
|
+
The [SDK API reference](docs/API_REFERENCE.md) maps every API operation to its Ruby method and documents exact
|
|
394
|
+
authentication, parameters, request bodies, success responses, and every published schema property.
|
|
395
|
+
|
|
396
|
+
## Complete document workflow
|
|
397
|
+
|
|
398
|
+
Every call below returns the SDK value after response-envelope handling. Use the
|
|
399
|
+
[API operation table](docs/API_REFERENCE.md#api-operations) for each method's exact HTTP authentication,
|
|
400
|
+
parameters, request body, and success wire response. Named response objects link to the complete
|
|
401
|
+
[schema catalog](docs/API_REFERENCE.md#schema-catalog).
|
|
402
|
+
|
|
403
|
+
### 1. Configure a workspace client
|
|
404
|
+
|
|
405
|
+
```ruby
|
|
406
|
+
client = Assinafy::Client.new(
|
|
407
|
+
api_key: ENV.fetch('ASSINAFY_API_KEY'),
|
|
408
|
+
account_id: ENV.fetch('ASSINAFY_ACCOUNT_ID'),
|
|
409
|
+
base_url: ENV.fetch('ASSINAFY_BASE_URL', 'https://api.assinafy.com.br/v1')
|
|
410
|
+
)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Use one authentication credential per client. Account-scoped methods use the configured account unless an
|
|
414
|
+
explicit `account_id_override` is supplied.
|
|
415
|
+
|
|
416
|
+
### 2. Upload a document or select a template
|
|
417
|
+
|
|
418
|
+
```ruby
|
|
419
|
+
document = client.documents.upload(
|
|
420
|
+
{ file_path: './contract.pdf' },
|
|
421
|
+
name: 'Customer agreement'
|
|
422
|
+
)
|
|
423
|
+
# => Document
|
|
424
|
+
|
|
425
|
+
template = client.templates.get('template-id')
|
|
426
|
+
# => Template
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
For in-memory data, pass `{ buffer: pdf_bytes, file_name: 'contract.pdf' }`. Upload requests are multipart;
|
|
430
|
+
template-based document creation is shown after the signer is available.
|
|
431
|
+
|
|
432
|
+
### 3. Wait for document processing
|
|
433
|
+
|
|
434
|
+
```ruby
|
|
435
|
+
document = client.documents.wait_until_ready(
|
|
436
|
+
document.fetch('id'),
|
|
437
|
+
max_wait_seconds: 60,
|
|
438
|
+
poll_interval_seconds: 2
|
|
439
|
+
)
|
|
440
|
+
# => Document with a ready status and populated pages
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
The helper raises `Assinafy::ValidationError` for invalid interval values and `Assinafy::Error` for a failed
|
|
444
|
+
terminal document status or timeout.
|
|
445
|
+
|
|
446
|
+
### 4. Create or reuse a signer
|
|
447
|
+
|
|
448
|
+
```ruby
|
|
449
|
+
signer = client.signers.find_by_email('signer@example.com') ||
|
|
450
|
+
client.signers.create(full_name: 'Example Signer', email: 'signer@example.com')
|
|
451
|
+
# => Signer
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### 5. Estimate and request signatures
|
|
455
|
+
|
|
456
|
+
```ruby
|
|
457
|
+
signer_request = {
|
|
458
|
+
id: signer.fetch('id'),
|
|
459
|
+
verification_method: 'Email',
|
|
460
|
+
notification_methods: ['Email'],
|
|
461
|
+
step: 1
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
cost = client.assignments.estimate_cost(
|
|
465
|
+
document.fetch('id'),
|
|
466
|
+
signers: [signer_request]
|
|
467
|
+
)
|
|
468
|
+
# => CostEstimate
|
|
469
|
+
|
|
470
|
+
assignment = client.assignments.create(
|
|
471
|
+
document.fetch('id'),
|
|
472
|
+
method: 'virtual',
|
|
473
|
+
signers: [signer_request],
|
|
474
|
+
message: 'Please review and sign.',
|
|
475
|
+
expires_at: '2026-12-31T23:59:00Z'
|
|
476
|
+
)
|
|
477
|
+
# => Assignment, including signing_urls
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
The template alternative binds a signer to a template role and creates the document and assignment together:
|
|
481
|
+
|
|
482
|
+
```ruby
|
|
483
|
+
role_signer = {
|
|
484
|
+
role_id: template.fetch('roles').first.fetch('id'),
|
|
485
|
+
id: signer.fetch('id'),
|
|
486
|
+
verification_method: 'Email',
|
|
487
|
+
notification_methods: ['Email']
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
template_cost = client.documents.estimate_cost_from_template(template.fetch('id'), [role_signer])
|
|
491
|
+
# => CostEstimate
|
|
492
|
+
|
|
493
|
+
template_document = client.documents.create_from_template(
|
|
494
|
+
template.fetch('id'),
|
|
495
|
+
[role_signer],
|
|
496
|
+
name: 'Customer agreement', message: 'Please review and sign.'
|
|
497
|
+
)
|
|
498
|
+
# => Document with an embedded Assignment
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### 6. Complete the signer flow
|
|
502
|
+
|
|
503
|
+
Signer-facing calls use the one-time access code delivered by Assinafy. They do not use the workspace API key.
|
|
504
|
+
|
|
505
|
+
```ruby
|
|
506
|
+
signing = Assinafy::Client.new(base_url: ENV.fetch('ASSINAFY_BASE_URL'))
|
|
507
|
+
access_code = ENV.fetch('ASSINAFY_SIGNER_ACCESS_CODE')
|
|
508
|
+
verification_code = ENV.fetch('ASSINAFY_VERIFICATION_CODE')
|
|
509
|
+
|
|
510
|
+
signer_data = signing.signers.self_data(signer_access_code: access_code)
|
|
511
|
+
signing.signers.accept_terms(signer_access_code: access_code) unless signer_data['has_accepted_terms']
|
|
512
|
+
signing.signers.verify_email(
|
|
513
|
+
verification_code: verification_code,
|
|
514
|
+
signer_access_code: access_code
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
signing_document = signing.assignments.signer_document(signer_access_code: access_code)
|
|
518
|
+
signing.signer_documents.sign_multiple(
|
|
519
|
+
[signing_document.fetch('id')],
|
|
520
|
+
signer_access_code: access_code
|
|
521
|
+
)
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
The virtual assignment created above uses `sign_multiple`. For a collect assignment, submit each positioned
|
|
525
|
+
item through `assignments.sign`:
|
|
526
|
+
|
|
527
|
+
```ruby
|
|
528
|
+
collect_items = signing_document.fetch('assignment').fetch('items').map do |item|
|
|
529
|
+
{
|
|
530
|
+
item_id: item.fetch('id'),
|
|
531
|
+
field_id: item.dig('field', 'id'),
|
|
532
|
+
page_id: item.dig('page', 'id'),
|
|
533
|
+
value: 'Accepted'
|
|
534
|
+
}
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
signing.assignments.sign(
|
|
538
|
+
signing_document.fetch('id'),
|
|
539
|
+
signing_document.dig('assignment', 'id'),
|
|
540
|
+
collect_items,
|
|
541
|
+
signer_access_code: access_code
|
|
542
|
+
)
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
The SDK maps the documented snake_case item keys to the API's camelCase request keys.
|
|
546
|
+
|
|
547
|
+
`DigitalCertificate` may be supplied as an assignment verification method. Provider documentation refers to
|
|
548
|
+
`/signers/certificate/start` and `/signers/certificate/complete`, but their authentication and request/response
|
|
549
|
+
schemas are not published in the API v1 machine contract, so the SDK does not expose those completion calls.
|
|
550
|
+
Contact Assinafy before enabling a digital-certificate signing flow in production.
|
|
551
|
+
|
|
552
|
+
### 7. Inspect, tag, download, and verify
|
|
553
|
+
|
|
554
|
+
```ruby
|
|
555
|
+
document_id = document.fetch('id')
|
|
556
|
+
|
|
557
|
+
activities = client.documents.activities(document_id) # => Array<DocumentActivity>
|
|
558
|
+
tags = client.documents.append_tags(document_id, ['tag-id']) # => Array<Tag>
|
|
559
|
+
client.documents.replace_tags(document_id, tags.map { |tag| tag.fetch('id') })
|
|
560
|
+
|
|
561
|
+
original_pdf = client.documents.download(document_id, 'original')
|
|
562
|
+
signed_pdf = client.documents.download(document_id, 'pades')
|
|
563
|
+
certificate_pdf = client.documents.download(document_id, 'certificated')
|
|
564
|
+
|
|
565
|
+
verification = client.documents.verify('signature-hash-from-assinafy')
|
|
566
|
+
# => DocumentVerification; inspect verification['is_valid']
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
`verify` returns Assinafy's verification result. It does not independently validate the PDF signature or its
|
|
570
|
+
certificate chain; see [Authentication and safety](docs/API_REFERENCE.md#authentication-and-safety).
|
|
571
|
+
|
|
572
|
+
### 8. Handle errors and clean up
|
|
573
|
+
|
|
574
|
+
```ruby
|
|
575
|
+
begin
|
|
576
|
+
client.documents.details(document_id)
|
|
577
|
+
rescue Assinafy::ValidationError => e
|
|
578
|
+
warn e.errors.inspect
|
|
579
|
+
rescue Assinafy::ApiError => e
|
|
580
|
+
warn "Assinafy returned #{e.status_code}: #{e.message}"
|
|
581
|
+
rescue Assinafy::NetworkError => e
|
|
582
|
+
warn "Network failure: #{e.message}"
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
client.documents.delete(document_id)
|
|
586
|
+
client.signers.delete(signer.fetch('id'))
|
|
587
|
+
client.templates.delete(template.fetch('id')) if template
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Delete resources only after downstream work is complete. Some resources can return `409` while processing or
|
|
591
|
+
while still referenced; retry only after resolving the reported state.
|
|
386
592
|
|
|
387
593
|
## Pagination
|
|
388
594
|
|
|
@@ -431,16 +637,26 @@ All inherit a `#context` Hash with debugging metadata.
|
|
|
431
637
|
## Tests
|
|
432
638
|
|
|
433
639
|
```bash
|
|
434
|
-
bundle exec rake spec #
|
|
640
|
+
bundle exec rake spec # 300+ RSpec examples, including a coverage matrix
|
|
435
641
|
bundle exec rubocop # Linting
|
|
642
|
+
bundle exec steep check # Static type checking against the published RBS
|
|
436
643
|
bundle exec bundler-audit check # Dependency CVEs
|
|
644
|
+
ruby scripts/check_api_contract.rb --file path/to/openapi.json # validate a local contract document
|
|
437
645
|
```
|
|
438
646
|
|
|
439
|
-
The coverage spec
|
|
647
|
+
The coverage spec validates the committed route-to-method inventory, public wrappers, aliases, and resource mappings without network access.
|
|
648
|
+
|
|
649
|
+
Ordinary pull-request CI remains network-independent. A weekly scheduled job runs
|
|
650
|
+
`scripts/check_api_contract.rb` against the upstream document. When Assinafy publishes a new contract, update
|
|
651
|
+
the SDK implementation, tests, API reference, and expected fixture together.
|
|
440
652
|
|
|
441
653
|
### Live integration tests
|
|
442
654
|
|
|
443
|
-
The suite in [`spec/integration/`](spec/integration/live_sandbox_spec.rb) exercises
|
|
655
|
+
The suite in [`spec/integration/`](spec/integration/live_sandbox_spec.rb) exercises safe sandbox workflows across
|
|
656
|
+
every workspace resource. Signer-code, OTP, password, social-login, API-key mutation, signature upload, and
|
|
657
|
+
irreversible sign/decline calls are wire-contract tested in the default suite but are not live-automated without
|
|
658
|
+
their one-time credentials or explicit state changes. The live suite is excluded from the default run and only
|
|
659
|
+
executes when `ASSINAFY_LIVE=1` is set with credentials:
|
|
444
660
|
|
|
445
661
|
```bash
|
|
446
662
|
ASSINAFY_LIVE=1 \
|
|
@@ -454,6 +670,10 @@ bundle exec rspec spec/integration
|
|
|
454
670
|
|
|
455
671
|
> These tests create and clean up real resources and, for the assignment flow, send real signature-request emails to the addresses in `ASSINAFY_TEST_EMAIL` / `ASSINAFY_TEST_EMAIL2`.
|
|
456
672
|
|
|
673
|
+
GitHub Actions provides the manual **Live Sandbox** workflow. Select a protected environment containing
|
|
674
|
+
`ASSINAFY_API_KEY`, `ASSINAFY_ACCOUNT_ID`, `ASSINAFY_TEST_EMAIL`, and `ASSINAFY_TEST_EMAIL2`; environment
|
|
675
|
+
branch/tag rules and approvals are applied before GitHub exposes those secrets to the job.
|
|
676
|
+
|
|
457
677
|
## Contributing
|
|
458
678
|
|
|
459
679
|
Pull requests and issues are welcome at <https://github.com/assinafy/ruby-sdk>.
|