unisender-ruby 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5816a7b213b4919d38f81de3568187d4dd1a2f345413b529f3961c2fad33f187
4
- data.tar.gz: 0c0dcea4ad0cb5f1e4a2f5d2a502562ff68d3edebe1fdc04c3c7e95675fc4a9f
3
+ metadata.gz: d06d19534449d52a259839973e260a8cd7e11cbc50c8136bf963b47c06f86624
4
+ data.tar.gz: b0de90f56f2838c27f6a1b3eea28654d45209cc4e3446b6f401ce6f31f005d35
5
5
  SHA512:
6
- metadata.gz: 2d6e970aa069fb618f59335fc935ec897f4513af963ab60728c8379072a88bdf06eb08103e7b67a942d283e3e0b308c3a546aa91e26d0a26ee8c1089a158789b
7
- data.tar.gz: '09e933af3af43cd61bb7c03a9a8c852813b24f22c766e4d1446008c1bddadb4c2d24d964a919272f489ab78c78ea73e40f5e598bb24570164b3f57b342f1b474'
6
+ metadata.gz: 44c26c949db6f70ef169a21b2e2c523640cb3ead8d4b551aa6412dea828bf3bee6c874e162b3cfb3292534721d14b4d1ec114bfd58c4433a07e99f5e496dddbd
7
+ data.tar.gz: 5d554001273bfd9562c6968fcffe3f1b98c6706093dae5bcfee8f890ad08fb75486cafb418956776c976af581c41ddd8cb7f9f4c2ae29502e17624923c468816
data/CHANGELOG.md CHANGED
@@ -1,7 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ Unreleased collects changes for the next version. Dated sections list user-visible changes, newest first. GitHub release notes reproduce the corresponding section.
4
+
3
5
  ## Unreleased
4
6
 
7
+ ## 0.1.1 - 2026-10-25
8
+
9
+ - Clarify installation, example destinations, contribution guidance, and maintainer policies.
10
+ - Include security, conduct, and release verification documents in the gem.
11
+ - Publish signed releases through an approval-gated workflow with an exact-file SPDX inventory and verifiable release assets.
12
+
5
13
  ## 0.1.0 - 2026-10-25
6
14
 
7
15
  - Publish as `unisender-ruby`; load with `require "unisender"` and use the `Unisender` namespace.
@@ -0,0 +1,90 @@
1
+
2
+ # Contributor Covenant 3.0 Code of Conduct
3
+
4
+ ## Our Pledge
5
+
6
+ We pledge to make our community welcoming, safe, and equitable for all.
7
+
8
+ We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant.
9
+
10
+
11
+ ## Encouraged Behaviors
12
+
13
+ While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language.
14
+
15
+ With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:
16
+
17
+ 1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
18
+ 2. Engaging **kindly and honestly** with others.
19
+ 3. Respecting **different viewpoints** and experiences.
20
+ 4. **Taking responsibility** for our actions and contributions.
21
+ 5. Gracefully giving and accepting **constructive feedback**.
22
+ 6. Committing to **repairing harm** when it occurs.
23
+ 7. Behaving in other ways that promote and sustain the **well-being of our community**.
24
+
25
+
26
+ ## Restricted Behaviors
27
+
28
+ We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.
29
+
30
+ 1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.
31
+ 2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.
32
+ 3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits.
33
+ 4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.
34
+ 5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission.
35
+ 6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.
36
+ 7. Behaving in other ways that **threaten the well-being** of our community.
37
+
38
+ ### Other Restrictions
39
+
40
+ 1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.
41
+ 2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
42
+ 3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community.
43
+ 4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors.
44
+
45
+
46
+ ## Reporting an Issue
47
+
48
+ Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm.
49
+
50
+ When an incident does occur, it is important to report it promptly. To report a possible violation, email [Leonid Svyatov](mailto:leonid@svyatov.com). Leonid moderates this community and will respond within seven days.
51
+
52
+ Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution.
53
+
54
+
55
+ ## Addressing and Repairing Harm
56
+
57
+ If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped.
58
+
59
+ 1) Warning
60
+ 1) Event: A violation involving a single incident or series of incidents.
61
+ 2) Consequence: A private, written warning from the Community Moderators.
62
+ 3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.
63
+ 2) Temporarily Limited Activities
64
+ 1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.
65
+ 2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members.
66
+ 3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over.
67
+ 3) Temporary Suspension
68
+ 1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation.
69
+ 2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions.
70
+ 3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted.
71
+ 4) Permanent Ban
72
+ 1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member.
73
+ 2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior.
74
+ 3) Repair: There is no possible repair in cases of this severity.
75
+
76
+ This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community.
77
+
78
+
79
+ ## Scope
80
+
81
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
82
+
83
+
84
+ ## Attribution
85
+
86
+ This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).
87
+
88
+ Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/)
89
+
90
+ For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion).
data/CONTRIBUTING.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Contributing
2
2
 
3
- This repository is private. Collaborators can use the [issue tracker](https://github.com/svyatov/unisender-ruby/issues). Include the Ruby and gem versions, a minimal example with fake values, expected behavior, and a redacted exception message. Do not post API keys, contact data, export links, or raw request/response bodies.
3
+ Contributions and questions are welcome through the [issue tracker](https://github.com/svyatov/unisender-ruby/issues). Include the Ruby and gem versions, a minimal example with fake values, expected behavior, and a redacted exception message. Do not post API keys, contact data, export links, or raw request/response bodies.
4
4
 
5
5
  ## Set up
6
6
 
@@ -13,10 +13,16 @@ bundle exec rake check
13
13
 
14
14
  `bin/setup` installs development dependencies and Lefthook hooks. The complete check runs offline tests, RuboCop, RBS validation, Steep for the library and consumer examples, the dependency vulnerability audit, and the gem build. The audit updates its advisory database and needs network access.
15
15
 
16
+ CI runs `bundle exec rake ci` for lint, tests, types, and the build. Dependency review blocks newly introduced vulnerabilities. A separate advisory job reports vulnerabilities across the lockfile without blocking unrelated changes.
17
+
16
18
  ## Make a change
17
19
 
18
20
  Use a branch such as `fix/error-context` or `feat/new-operation`. Read the official UniSender method documentation before changing a wire contract. Add a regression test with a deterministic transport, keep signatures in `sig/` synchronized, update the relevant docs, and add an entry under Unreleased in [CHANGELOG.md](CHANGELOG.md).
19
21
 
22
+ Follow the repository requirements in [AGENTS.md](AGENTS.md) and the [code of conduct](CODE_OF_CONDUCT.md). New functionality must include tests.
23
+
24
+ Fork the repository and create your branch from `main`. Push the branch to your fork, then open a pull request against `svyatov/unisender-ruby:main`. Describe the affected public interface and include the evidence needed to assess the change. Keep unrelated changes in separate pull requests. Maintainers use squash merges.
25
+
20
26
  | Command | Purpose |
21
27
  | --- | --- |
22
28
  | `bundle exec rake test` | Minitest with 100% line and branch coverage across `lib/` and `scripts/` |
@@ -35,9 +41,15 @@ Pre-commit hooks scan staged changes for secrets, apply and stage safe Ruby form
35
41
 
36
42
  ```sh
37
43
  bundle exec rake build
38
- gem install --local ./pkg/unisender-ruby-0.1.0.gem
44
+ gem install --local ./pkg/unisender-ruby-0.1.1.gem
39
45
  ```
40
46
 
41
47
  From outside the checkout, run `ruby -runisender -e 'puts Unisender::VERSION'`. For an isolated check, use a temporary `GEM_HOME` and `GEM_PATH`, and run the examples with a fake transport. The gem includes examples and RBS signatures; development dependencies are not runtime dependencies.
42
48
 
43
49
  Routine verification must not call a live account, send messages, or change contacts. Live checks require explicit authorization and a designated test account. Publishing and releases are separate maintainer actions.
50
+
51
+ ## Maintainer decisions
52
+
53
+ Leonid Svyatov is the sole maintainer and decides which changes merge and which versions are released. No successor is arranged if he stops maintaining the project.
54
+
55
+ Report vulnerabilities privately using [SECURITY.md](SECURITY.md).
data/README.md CHANGED
@@ -1,18 +1,39 @@
1
1
  # Unisender
2
2
 
3
- A Ruby client for the [UniSender marketing API](https://www.unisender.com/ru/support/category/api/). Ruby 3.3 or newer, no runtime gem dependencies. This client targets `api.unisender.com`, not UniSender Go.
3
+ A Ruby client for applications using the [UniSender marketing API](https://www.unisender.com/ru/support/category/api/).
4
+
5
+ Ruby 3.3 or newer, no runtime gem dependencies. This client targets `api.unisender.com`, not UniSender Go.
4
6
 
5
7
  Explicit keyword methods cover contacts, lists, messages, campaigns, statistics, templates, fields, notes, and Event Tracking. Responses preserve upstream JSON, warnings, and HTTP metadata. See the [API reference](docs/api.md) for the operation index, argument types, and result shapes.
6
8
 
7
9
  ## Install
8
10
 
9
- Add the gem to your application's Gemfile:
11
+ Install the gem:
12
+
13
+ ```sh
14
+ gem install unisender-ruby
15
+ ```
16
+
17
+ Save this read-only example as `quickstart.rb`. It uses the key in `UNISENDER_API_KEY`:
18
+
19
+ <!-- example: examples/quickstart.rb -->
20
+ ```ruby
21
+ require "unisender"
22
+
23
+ client = Unisender::Client.new(api_key: ENV.fetch("UNISENDER_API_KEY"))
24
+ client.get_lists.result.each { |list| puts list.fetch("title") }
25
+ # Example output for a list named News: News
26
+ ```
27
+
28
+ Run `ruby quickstart.rb`. It prints one title per list, or nothing if the account has no lists. See [Make your first request](#make-your-first-request) for key setup.
29
+
30
+ For a Bundler project, add the gem to your application's Gemfile:
10
31
 
11
32
  ```ruby
12
- gem "unisender-ruby", "~> 0.1.0", require: "unisender"
33
+ gem "unisender-ruby", "~> 0.1.1", require: "unisender"
13
34
  ```
14
35
 
15
- Then run `bundle install`. To install it directly, run `gem install unisender-ruby`. The package is named `unisender-ruby`; load it with `require "unisender"`.
36
+ Then run `bundle install`. The package is named `unisender-ruby`; load it with `require "unisender"`.
16
37
 
17
38
  ### Install from a checkout
18
39
 
@@ -39,22 +60,14 @@ bundle exec ruby examples/check_connection.rb
39
60
 
40
61
  The check prints only the HTTP status and list count, including zero for an empty account. Failures exit with status 1. It does not print list names or IDs. The gem itself reads neither environment variables nor `.env`; application code passes the key explicitly.
41
62
 
42
- This example only reads your lists. It does not create contacts or send messages:
43
-
44
- <!-- example: examples/quickstart.rb -->
45
- ```ruby
46
- require "unisender"
47
-
48
- client = Unisender::Client.new(api_key: ENV.fetch("UNISENDER_API_KEY"))
49
- client.get_lists.result.each { |list| puts list.fetch("title") }
50
- ```
51
-
52
- Save it as `quickstart.rb` and run `bundle exec ruby quickstart.rb`. It prints one title per list, or nothing if the account has no lists. A missing environment variable raises `KeyError` before any request. To try the client without an account or network access, run `bundle exec ruby examples/offline.rb` from this checkout.
63
+ The `quickstart.rb` example above only reads lists. It does not create contacts or send messages. In a Bundler project, run it with `bundle exec ruby quickstart.rb`. A missing environment variable raises `KeyError` before any request. To try the client without an account or network access, run `bundle exec ruby examples/offline.rb` from this checkout.
53
64
 
54
65
  ## Subscribe a contact
55
66
 
56
67
  This operation changes your account and normally **sends a confirmation email**. Use an existing list ID from `get_lists`, and an address you control for a manual trial. Set `UNISENDER_LIST_ID` and `UNISENDER_CONTACT_EMAIL` before running it.
57
68
 
69
+ Save the following example as `subscribe.rb`:
70
+
58
71
  <!-- example: examples/subscribe.rb -->
59
72
  ```ruby
60
73
  require "unisender"
@@ -90,6 +103,8 @@ Every operation returns `Unisender::Response`: `result`, `warnings`, `data` (the
90
103
 
91
104
  Named methods use snake_case and reject unknown keywords. Optional `nil` values are omitted, preserving server defaults. API messages default to English; use `Client.new(api_key: ..., language: :ru)` for Russian. Message-level `lang:` is a separate setting.
92
105
 
106
+ Use this error handler in your application's `request.rb`:
107
+
93
108
  ```ruby
94
109
  begin
95
110
  client.get_lists
@@ -113,6 +128,8 @@ A successful envelope does not mean every recipient succeeded. Inspect `send_ema
113
128
 
114
129
  ## Timeouts, retries, and pagination
115
130
 
131
+ In `quickstart.rb`, replace the client construction with:
132
+
116
133
  ```ruby
117
134
  client = Unisender::Client.new(
118
135
  api_key: ENV.fetch("UNISENDER_API_KEY"),
@@ -135,6 +152,9 @@ RBS signatures ship with the gem. `Response[Result]` describes a named operation
135
152
 
136
153
  - [Contributing, local checks, and package verification](CONTRIBUTING.md)
137
154
  - [Changes and compatibility policy](CHANGELOG.md)
155
+ - [Release verification](docs/releases.md)
138
156
  - [Source repository](https://github.com/svyatov/unisender-ruby) and [issue reports](https://github.com/svyatov/unisender-ruby/issues)
139
157
 
140
- The repository is currently private; its GitHub links require access. Tests use fake credentials and deterministic responses. They do not establish compatibility with a live account. Released under the [MIT License](LICENSE.txt).
158
+ This project is maintained by Leonid Svyatov. Use the public [issue tracker](https://github.com/svyatov/unisender-ruby/issues) for questions and defect reports. Report vulnerabilities privately through [SECURITY.md](SECURITY.md).
159
+
160
+ Tests use fake credentials and deterministic responses. They do not establish compatibility with a live account. Released under the [MIT License](LICENSE.txt).
data/SECURITY.md ADDED
@@ -0,0 +1,13 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes target the latest published release. Upgrade to that release before reporting a problem when possible.
6
+
7
+ ## Report a vulnerability
8
+
9
+ Email [Leonid Svyatov](mailto:leonid@svyatov.com) privately. Expect an initial response within seven days.
10
+
11
+ Include the affected gem and Ruby versions, the security impact, and a minimal reproduction using fake credentials and contact data. Do not include live API keys, recipient data, or account exports. Do not disclose the vulnerability in a public issue before a fix or coordinated disclosure date is agreed.
12
+
13
+ The maintainer will assess the report and coordinate a fix and disclosure with you.
data/docs/releases.md ADDED
@@ -0,0 +1,22 @@
1
+ # Release verification
2
+
3
+ Version tags trigger `.github/workflows/release.yml`. Tests run before the build. The `release` environment requires maintainer approval before publication.
4
+
5
+ The workflow publishes through RubyGems trusted publishing. Its signing client is isolated in `.github/release/Gemfile.lock`. Runtime dependencies are defined only by `unisender.gemspec`.
6
+
7
+ Starting with 0.1.1, GitHub releases include the gem, an SPDX inventory of its packaged files, and SHA-256 checksums. The workflow attests all three assets. The inventory generator stops if runtime dependencies need additional inventory support.
8
+
9
+ Download and verify a release in your terminal:
10
+
11
+ ```sh
12
+ gh release download v0.1.1 --repo svyatov/unisender-ruby --dir release
13
+ cd release
14
+ gh attestation verify unisender-ruby.gem --repo svyatov/unisender-ruby --signer-workflow svyatov/unisender-ruby/.github/workflows/release.yml --source-ref refs/tags/v0.1.1
15
+ gh attestation verify sbom.spdx.json --repo svyatov/unisender-ruby --signer-workflow svyatov/unisender-ruby/.github/workflows/release.yml --source-ref refs/tags/v0.1.1
16
+ gh attestation verify SHA256SUMS --repo svyatov/unisender-ruby --signer-workflow svyatov/unisender-ruby/.github/workflows/release.yml --source-ref refs/tags/v0.1.1
17
+ shasum -a 256 -c SHA256SUMS
18
+ ```
19
+
20
+ RubyGems also serves the signing bundle for each published gem through its [attestation API](https://guides.rubygems.org/rubygems-org-api/#get---apiv1attestationsgem-name-versionjson). Compare the bundle with the exact gem version and the `release.yml` workflow identity.
21
+
22
+ The 0.1.0 tag and assets predate this workflow and remain unchanged. Its release notes follow the complete 0.1.0 changelog section.
@@ -4,3 +4,4 @@ require "unisender"
4
4
 
5
5
  client = Unisender::Client.new(api_key: ENV.fetch("UNISENDER_API_KEY"))
6
6
  client.get_lists.result.each { |list| puts list.fetch("title") }
7
+ # Example output for a list named News: News
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Unisender
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unisender-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leonid Svyatov
@@ -17,10 +17,13 @@ extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
19
  - CHANGELOG.md
20
+ - CODE_OF_CONDUCT.md
20
21
  - CONTRIBUTING.md
21
22
  - LICENSE.txt
22
23
  - README.md
24
+ - SECURITY.md
23
25
  - docs/api.md
26
+ - docs/releases.md
24
27
  - examples/campaign.rb
25
28
  - examples/check_connection.rb
26
29
  - examples/events.rb
@@ -81,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
84
  - !ruby/object:Gem::Version
82
85
  version: '0'
83
86
  requirements: []
84
- rubygems_version: 4.0.23
87
+ rubygems_version: 4.0.20
85
88
  specification_version: 4
86
89
  summary: Ruby client for the UniSender API.
87
90
  test_files: []