Skip to content

Add api token endpoints#107

Merged
IgorDobryn merged 8 commits intomainfrom
MT-21830-api-token-endpoints
May 4, 2026
Merged

Add api token endpoints#107
IgorDobryn merged 8 commits intomainfrom
MT-21830-api-token-endpoints

Conversation

@IgorDobryn
Copy link
Copy Markdown
Contributor

@IgorDobryn IgorDobryn commented Apr 29, 2026

Motivation

Changes

  • POST /api/accounts/{account_id}/api_tokens
  • GET /api/accounts/{account_id}/api_tokens/{id}
  • DELETE /api/accounts/{account_id}/api_tokens/{id}
  • POST /api/accounts/{account_id}/api_tokens/{id}/reset
  • GET /api/accounts/{account_id}/permissions/resources

Summary by CodeRabbit

Release Notes

  • New Features

    • Added API token management: retrieve, create, reset, and delete tokens
    • Added ability to fetch the permission resource tree for your account
    • Included example scripts demonstrating token and permissions operations
  • Tests

    • Added comprehensive test coverage for API token operations
    • Added test coverage for permission resources retrieval

body:
encoding: ASCII-8BIT
string: '{"resources":[{"resource_type":"account","resource_id":1719941,"access_level":100}],"id":2498713,"name":"Ruby
SDK Test Token","last_4_digits":"dcf7","created_by":"SDK Dev Account Token","expires_at":null,"token":"d5335b07610bd99b7fbc03f80e26dcf7"}'
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the token does not exist in real app already

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

This PR adds API token management and permission resource retrieval capabilities to the Mailtrap client library. It introduces ApiTokensAPI for token operations (get, create, reset, delete), a PermissionResource DTO for permission tree nodes, extends PermissionsAPI with resource tree fetching, provides example scripts, and includes comprehensive VCR fixtures and test coverage.

Changes

Token and Permission APIs

Layer / File(s) Summary
Data Models
lib/mailtrap/permission_resource.rb
New PermissionResource struct DTO with id, name, type, access_level, and nested resources fields for recursive permission tree representation.
API Token Implementation
lib/mailtrap/api_tokens_api.rb
Adds ApiTokensAPI class with supported_options configuration and public methods: get(token_id), create(options), reset(token_id), and delete(token_id) wrapping REST endpoints.
Permissions API Extension
lib/mailtrap/permissions_api.rb
Extends PermissionsAPI with resources method that fetches permission tree from /permissions/resources endpoint and recursively builds PermissionResource objects via private build_resource_tree helper.
Usage Examples
examples/api_tokens_api.rb, examples/permissions_api.rb
Demonstrates token lifecycle operations (list, fetch, create, reset, delete) and retrieving the recursive permission/resource tree structure.
Tests & Fixtures
spec/mailtrap/api_tokens_api_spec.rb, spec/mailtrap/permission_resource_spec.rb, spec/mailtrap/permissions_api_spec.rb, spec/fixtures/vcr_cassettes/...
RSpec specs validate correct response mapping to ApiToken and PermissionResource objects, error handling for missing tokens and invalid options, and VCR cassettes record all HTTP interactions including success and error cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • i7an
  • mklocek
  • leonid-shevtsov

Poem

🐰 Hop along, the tokens now dance,
Reset and delete at a glance!
Permission trees sprouted with care,
Resources recursive, nested with flair—
REST endpoints wrapped, API dreams share! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description lists the implemented endpoints but lacks motivation explanation and testing instructions required by the template. The 'How to test' and 'Images and GIFs' sections are entirely missing. Add a motivation section explaining why these endpoints were needed, and include a 'How to test' section with testing steps and checkboxes as specified in the template.
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add api token endpoints' accurately reflects the main changes: implementation of API token management methods (get, create, reset, delete) and the permissions resources endpoint.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MT-21830-api-token-endpoints

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@IgorDobryn IgorDobryn requested review from DagonWat and i7an April 29, 2026 14:39
@IgorDobryn IgorDobryn marked this pull request as ready for review April 29, 2026 14:39
# => #<struct Mailtrap::ApiToken id=12345, name="My API Token", ..., token="a1b2c3d4e5f6g7h8">

# Reset a token — expires the old value (short grace period) and returns a new value once.
api_tokens.reset(12_345)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it would be nice quality of life improvement to have api_tokens.reset(id: 12_345) so to explicitly define what is the route parameter.

Very optional

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would not be aligned with the rest of the endpoints e.g. get, delete, ...

Comment thread lib/mailtrap/api_tokens_api.rb Outdated
)
end

# Returns the recursive tree of resources the current token can access.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if that information is crucial for customer, to know that its a recursive tree, everywhere else we just mention that its permissions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather keep it

Base automatically changed from MT-21830-account-management-api to main May 4, 2026 09:01
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_create/maps_response_data_to_ApiToken_with_full_token_value.yml (1)

70-73: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Full API token value recorded in plaintext — fixture needs sanitization.

The response body at line 72 contains the actual full API token d5335b07610bd99b7fbc03f80e26dcf7. Even though the author confirmed this token no longer exists in the app, the raw value persists permanently in git history and sets an unsafe precedent. It should be replaced with a redacted placeholder.

🔐 Proposed fix
-      string: '{"resources":[{"resource_type":"account","resource_id":1719941,"access_level":100}],"id":2498713,"name":"Ruby
-        SDK Test Token","last_4_digits":"dcf7","created_by":"SDK Dev Account Token","expires_at":null,"token":"d5335b07610bd99b7fbc03f80e26dcf7"}'
+      string: '{"resources":[{"resource_type":"account","resource_id":1719941,"access_level":100}],"id":2498713,"name":"Ruby
+        SDK Test Token","last_4_digits":"dcf7","created_by":"SDK Dev Account Token","expires_at":null,"token":"<API_TOKEN_VALUE>"}'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_create/maps_response_data_to_ApiToken_with_full_token_value.yml`
around lines 70 - 73, The fixture contains a full API token in the recorded
response JSON under the "token" field; replace the cleartext value
("d5335b07610bd99b7fbc03f80e26dcf7") with a redacted placeholder (e.g.
"REDACTED_API_TOKEN") in the YAML string so the cassette no longer stores the
secret, and scan the same file for any other occurrences of that token and
replace them as well; keep the surrounding JSON structure and encoding unchanged
to avoid breaking playback.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_get/maps_response_data_to_ApiToken_object.yml`:
- Around line 69-73: The cassette contains a potential PII value: the JSON key
"created_by" currently set to "John Doe" in the recorded body of
maps_response_data_to_ApiToken_object.yml; confirm whether that was a real user
name and if so replace it with a sanitized placeholder (e.g. "<CREATED_BY>") by
editing the recorded body string to substitute "created_by":"John Doe" ->
"created_by":"<CREATED_BY>", then re-run the tests or re-record the fixture (or
run your VCR sanitization script) to ensure the placeholder is persisted; also
scan other cassettes for any remaining real-looking display names and sanitize
them similarly.

In
`@spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_reset/maps_response_data_to_ApiToken_with_new_token_value.yml`:
- Around line 69-74: The cassette records a real API token in the body.string
JSON under the "token" field; open the VCR fixture
maps_response_data_to_ApiToken_with_new_token_value.yml and sanitize the
body.string value by replacing the actual token value
("token":"ff828c557cb54180a0ce279fd6d5856f") with the same redacted placeholder
used in the _create cassette (e.g. "token":"<REDACTED_TOKEN>" or the project’s
standard placeholder), ensuring the JSON structure and ASCII-8BIT encoding
remain unchanged.

In
`@spec/fixtures/vcr_cassettes/Mailtrap_PermissionsAPI/_resources/returns_a_tree_of_PermissionResource_objects.yml`:
- Around line 1-74: The VCR cassettes currently scrub headers but not sensitive
values in response bodies; update the VCR configuration (the VCR.configure
block) to mask API tokens before recording by adding a filter or before_record
hook that inspects interaction.response.body and replaces token fields (e.g.,
JSON keys like "token", "plain_text_token", "access_token" or 32-char hex
strings such as /"[0-9a-f]{32}"/i) with a placeholder like "<API_TOKEN>";
implement this using VCR.filter_sensitive_data or VCR.configure { |c|
c.before_record { |i| i.response.body.gsub!(regex, '"<API_TOKEN>"') } } so
future cassettes (including the ApiTokensAPI-related cassettes) never store raw
tokens.

---

Duplicate comments:
In
`@spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_create/maps_response_data_to_ApiToken_with_full_token_value.yml`:
- Around line 70-73: The fixture contains a full API token in the recorded
response JSON under the "token" field; replace the cleartext value
("d5335b07610bd99b7fbc03f80e26dcf7") with a redacted placeholder (e.g.
"REDACTED_API_TOKEN") in the YAML string so the cassette no longer stores the
secret, and scan the same file for any other occurrences of that token and
replace them as well; keep the surrounding JSON structure and encoding unchanged
to avoid breaking playback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ed551991-2039-4a2c-9114-fa7527bfe1d5

📥 Commits

Reviewing files that changed from the base of the PR and between b4d3fec and 0887495.

📒 Files selected for processing (17)
  • examples/api_tokens_api.rb
  • examples/permissions_api.rb
  • lib/mailtrap/api_tokens_api.rb
  • lib/mailtrap/permission_resource.rb
  • lib/mailtrap/permissions_api.rb
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_create/maps_response_data_to_ApiToken_with_full_token_value.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_create/when_name_is_missing/raises_a_Mailtrap_Error.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_delete/returns_nil_on_success.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_delete/when_token_does_not_exist/raises_not_found_error.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_get/maps_response_data_to_ApiToken_object.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_get/when_token_does_not_exist/raises_not_found_error.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_reset/maps_response_data_to_ApiToken_with_new_token_value.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_reset/when_token_does_not_exist/raises_not_found_error.yml
  • spec/fixtures/vcr_cassettes/Mailtrap_PermissionsAPI/_resources/returns_a_tree_of_PermissionResource_objects.yml
  • spec/mailtrap/api_tokens_api_spec.rb
  • spec/mailtrap/permission_resource_spec.rb
  • spec/mailtrap/permissions_api_spec.rb

Comment on lines +69 to +74
body:
encoding: ASCII-8BIT
string: '{"resources":[{"resource_type":"account","resource_id":1719941,"access_level":100}],"id":2498715,"name":"Ruby
SDK Test Token 2498715","last_4_digits":"856f","created_by":"SDK Dev Account
Token","expires_at":null,"token":"ff828c557cb54180a0ce279fd6d5856f"}'
recorded_at: Wed, 29 Apr 2026 14:25:08 GMT
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Full API token value recorded in plaintext — fixture must be sanitized.

Line 73 embeds the actual API token ff828c557cb54180a0ce279fd6d5856f (newly generated by the reset operation) in the VCR cassette. This is a live credential at the time of recording; even after expiry it remains in git history and creates a credential-in-source pattern that should be avoided across all fixtures. Replace with a redacted placeholder consistent with the approach needed in the _create cassette.

🔐 Proposed fix
-      string: '{"resources":[{"resource_type":"account","resource_id":1719941,"access_level":100}],"id":2498715,"name":"Ruby
-        SDK Test Token 2498715","last_4_digits":"856f","created_by":"SDK Dev Account
-        Token","expires_at":null,"token":"ff828c557cb54180a0ce279fd6d5856f"}'
+      string: '{"resources":[{"resource_type":"account","resource_id":1719941,"access_level":100}],"id":2498715,"name":"Ruby
+        SDK Test Token 2498715","last_4_digits":"856f","created_by":"SDK Dev Account
+        Token","expires_at":null,"token":"<API_TOKEN_VALUE>"}'
🧰 Tools
🪛 Betterleaks (1.1.2)

[high] 73-73: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@spec/fixtures/vcr_cassettes/Mailtrap_ApiTokensAPI/_reset/maps_response_data_to_ApiToken_with_new_token_value.yml`
around lines 69 - 74, The cassette records a real API token in the body.string
JSON under the "token" field; open the VCR fixture
maps_response_data_to_ApiToken_with_new_token_value.yml and sanitize the
body.string value by replacing the actual token value
("token":"ff828c557cb54180a0ce279fd6d5856f") with the same redacted placeholder
used in the _create cassette (e.g. "token":"<REDACTED_TOKEN>" or the project’s
standard placeholder), ensuring the JSON structure and ASCII-8BIT encoding
remain unchanged.

# => [
# #<struct Mailtrap::PermissionResource id=4001, name="My First Project", type="project",
# access_level=1, resources=[
# #<struct Mailtrap::PermissionResource id=3816, name="My First Inbox", type="inbox",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a suggestion, lets maybe not expose inboxes and choose another resource so its easier to later to remove all the mentions.

@IgorDobryn IgorDobryn merged commit f9a59f9 into main May 4, 2026
4 checks passed
@IgorDobryn IgorDobryn deleted the MT-21830-api-token-endpoints branch May 4, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants