ask-sentry 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fc6dc184f307c3a0661dbc52d48c8caee86d7a5309ca627993cd37312686509f
4
+ data.tar.gz: 5e7484e41f6915948497575f26a28d681da5665fee6f796189498458f4bb1d09
5
+ SHA512:
6
+ metadata.gz: 4e2f9dce7c5a47978ecd41fe1696111472158c1e8e5c4f62db6b7d926483a91e8188267b8b27254e422d71d4e3a4831920020da7489a005cfdec816219c4a5d6
7
+ data.tar.gz: 3ef0390e2ffa88cc75fdb6b1df2260c1da15a1e5c05548e5f4547899fd05c761309db5b03408835b2c826d9de0c8db420ce54d4f19f53305ad246012e3b9e228
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-06-10)
4
+
5
+ - Initial release
6
+ - `Ask::Sentry.client` — authenticated Faraday client for the Sentry REST API
7
+ - `Ask::Sentry.recent_errors` — convenience wrapper to fetch recent issues
8
+ - `Ask::Sentry.issue_events` — convenience wrapper to fetch issue events
9
+ - `Ask::Sentry::Errors` — structured error knowledge for common HTTP codes, rate limits, pagination
10
+ - Auth token resolution via `Ask::Auth.resolve(:sentry_token)`
11
+ - 401 response detection with `Ask::Auth::InvalidCredential` error
12
+ - Faraday retry middleware (3 retries, exponential backoff)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kaka Ruto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # ask-sentry
2
+
3
+ Sentry — error tracking via the Sentry API
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem "ask-sentry"
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ruby
14
+ client = Ask::Sentry.client
15
+ # ... use the client according to its API
16
+ ```
17
+
18
+ ## Development
19
+
20
+ ```bash
21
+ bundle exec rake test
22
+ ```
23
+
24
+ ## License
25
+
26
+ MIT
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "faraday/retry"
5
+ require "ask/auth"
6
+
7
+ module Ask
8
+ module Sentry
9
+ # Returns an authenticated Faraday client configured for the Sentry REST API.
10
+ #
11
+ # Resolves the Sentry token via +Ask::Auth.resolve(:sentry_token)+ and
12
+ # configures the client with sensible defaults:
13
+ #
14
+ # - +base URL+: +https://sentry.io/api/0/+
15
+ # - +Authorization+: Bearer token
16
+ # - +middleware+: Faraday retry middleware (3 retries, exponential backoff)
17
+ #
18
+ # The client is wrapped in a +ClientProxy+ that converts
19
+ # HTTP 401 responses into +Ask::Auth::InvalidCredential+.
20
+ #
21
+ # @example
22
+ # client = Ask::Sentry.client
23
+ # issues = client.get("projects/myorg/myapp/issues/")
24
+ #
25
+ # @return [ClientProxy] an authenticated HTTP client
26
+ # @raise [Ask::Auth::MissingCredential] if no Sentry token is configured
27
+ # @raise [Ask::Auth::InvalidCredential] if the token is rejected (401)
28
+ def self.client
29
+ token = Ask::Auth.resolve(:sentry_token)
30
+
31
+ client = Faraday.new(url: "https://sentry.io/api/0/") do |f|
32
+ f.request :authorization, :Bearer, token
33
+ f.headers["Content-Type"] = "application/json"
34
+ f.request :retry, max: 3, interval: 1, backoff_factor: 2,
35
+ retry_statuses: [429, 500, 502, 503]
36
+ f.adapter Faraday.default_adapter
37
+ end
38
+
39
+ ClientProxy.new(client)
40
+ end
41
+
42
+ # Convenience wrapper to fetch recent errors for a given organization and project.
43
+ #
44
+ # @param organization [String] Sentry organization slug
45
+ # @param project [String] Sentry project slug
46
+ # @param limit [Integer] Maximum number of issues to return (default: 10)
47
+ # @return [Faraday::Response] API response
48
+ def self.recent_errors(organization:, project:, limit: 10)
49
+ client.get("projects/#{organization}/#{project}/issues/") do |req|
50
+ req.params[:limit] = limit
51
+ end
52
+ end
53
+
54
+ # Convenience wrapper to fetch events for a specific issue.
55
+ #
56
+ # @param issue_id [Integer, String] Sentry issue ID
57
+ # @param limit [Integer] Maximum number of events to return (default: 10)
58
+ # @return [Faraday::Response] API response
59
+ def self.issue_events(issue_id, limit: 10)
60
+ client.get("issues/#{issue_id}/events/") do |req|
61
+ req.params[:limit] = limit
62
+ end
63
+ end
64
+
65
+ # Proxies method calls to a +Faraday::Connection+, converting 401 responses
66
+ # into +Ask::Auth::InvalidCredential+.
67
+ class ClientProxy < BasicObject
68
+ def initialize(client)
69
+ @client = client
70
+ end
71
+
72
+ def method_missing(name, ...)
73
+ response = @client.public_send(name, ...)
74
+
75
+ if response.is_a?(::Faraday::Response) && response.status == 401
76
+ ::Kernel.raise ::Ask::Auth::InvalidCredential, :sentry_token
77
+ end
78
+
79
+ response
80
+ end
81
+
82
+ def respond_to_missing?(name, include_private = false)
83
+ @client.respond_to?(name, include_private) || super
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ask
4
+ module Sentry
5
+ # Human-readable description of the Sentry service context.
6
+ DESCRIPTION = "Sentry — error tracking via the Sentry API"
7
+
8
+ # Base URL for Sentry REST API documentation.
9
+ DOCS_URL = "https://docs.sentry.io/api/"
10
+
11
+ # URL for the Sentry OpenAPI specification.
12
+ OPENAPI_URL = "https://sentry.io/api/0/"
13
+
14
+ # Credential name used with Ask::Auth.resolve.
15
+ AUTH_NAME = :sentry_token
16
+
17
+ # Instructions for obtaining a Sentry auth token.
18
+ AUTH_HOW = "https://sentry.io/settings/account/api/auth-tokens/"
19
+
20
+ # Gem name for the HTTP client.
21
+ GEM_NAME = "faraday"
22
+
23
+ # Required gem version constraint.
24
+ GEM_VERSION = "~> 2.0"
25
+
26
+ # URL for Faraday library documentation.
27
+ GEM_DOCS = "https://lostisland.github.io/faraday"
28
+
29
+ # Quick-start Ruby code snippet for agents to copy-paste.
30
+ QUICK_START = <<~RUBY
31
+ client = Ask::Sentry.client
32
+ issues = client.get("/api/0/projects/ORG/PROJECT/issues/", limit: 10)
33
+
34
+ # Or use the helper:
35
+ Ask::Sentry.recent_errors(organization: "myorg", project: "myapp", limit: 10)
36
+ RUBY
37
+ end
38
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ask
4
+ module Sentry
5
+ # Structured error knowledge for AI agents working with the Sentry API.
6
+ #
7
+ # Provides human-readable guidance for common HTTP status codes, rate
8
+ # limiting, pagination, and authentication errors encountered when
9
+ # using the Faraday-based Sentry client.
10
+ module Errors
11
+ # Rate limit information.
12
+ #
13
+ # - Sentry rate limits are based on the plan (see Sentry docs).
14
+ # - When rate-limited, the API returns 429 Too Many Requests.
15
+ # - The agent should wait for the Retry-After header and retry.
16
+ RATE_LIMIT = {
17
+ description: "Sentry rate limits vary by plan. See https://docs.sentry.io/api/rate-limiting/",
18
+ error_status: 429,
19
+ action: "Wait for the Retry-After header duration, then retry the request."
20
+ }.freeze
21
+
22
+ # Common HTTP status codes returned by the Sentry API and how to handle them.
23
+ STATUS_CODES = {
24
+ 200 => "OK — Request succeeded.",
25
+ 201 => "Created — Resource was created successfully.",
26
+ 202 => "Accepted — Request accepted for processing.",
27
+ 204 => "No Content — Request succeeded, no response body.",
28
+ 400 => "Bad Request — Invalid request parameters. Check the request body.",
29
+ 401 => "Unauthorized — Auth token is missing, invalid, or revoked. Re-authenticate.",
30
+ 403 => "Forbidden — Token lacks the required scopes for this resource.",
31
+ 404 => "Not Found — The requested resource does not exist.",
32
+ 409 => "Conflict — Resource state conflict.",
33
+ 413 => "Payload Too Large — Request body exceeds the maximum size limit.",
34
+ 429 => "Too Many Requests — Rate limit exceeded. Wait before retrying.",
35
+ 500 => "Internal Server Error — Sentry server issue. Retry with backoff.",
36
+ 502 => "Bad Gateway — Sentry upstream issue. Retry with backoff.",
37
+ 503 => "Service Unavailable — Sentry is temporarily unavailable. Retry later."
38
+ }.freeze
39
+
40
+ # Pagination guidance for large result sets.
41
+ PAGINATION = {
42
+ link_header: "Sentry uses Link headers for pagination. The Faraday client receives these in the response headers.",
43
+ cursor_based: "Sentry uses cursor-based pagination via the 'Link' header with 'rel=\"next\"' and 'rel=\"previous\"'.",
44
+ per_page: "Use the 'limit' query parameter to control page size.",
45
+ max_results: "For large queries, paginate using cursor values from the Link header."
46
+ }.freeze
47
+
48
+ # Map of error scenarios to human-readable guidance.
49
+ EXCEPTIONS = {
50
+ "Faraday::UnauthorizedError" => {
51
+ message: "Your Sentry auth token is invalid or has been revoked.",
52
+ action: "Generate a new token at https://sentry.io/settings/account/api/auth-tokens/ with the necessary scopes."
53
+ },
54
+ "Faraday::ForbiddenError" => {
55
+ message: "Your token lacks the required permissions for this operation.",
56
+ action: "Check your token scopes at https://sentry.io/settings/account/api/auth-tokens/."
57
+ },
58
+ "Faraday::ResourceNotFound" => {
59
+ message: "The requested project, issue, or resource does not exist.",
60
+ action: "Verify the organization slug, project slug, and resource identifiers."
61
+ },
62
+ "Faraday::TimeoutError" => {
63
+ message: "The request to Sentry timed out.",
64
+ action: "Check Sentry service status at https://status.sentry.io/ and retry the request."
65
+ },
66
+ "Faraday::TooManyRequestsError" => {
67
+ message: "Sentry API rate limit exceeded.",
68
+ action: "Check the Retry-After response header, wait the specified duration, then retry."
69
+ },
70
+ "Faraday::ClientError" => {
71
+ message: "Sentry API returned a client error (4xx).",
72
+ action: "Check the request parameters, auth token, and resource identifiers."
73
+ },
74
+ "Faraday::ServerError" => {
75
+ message: "Sentry API returned a server error (5xx).",
76
+ action: "Retry with exponential backoff. If the issue persists, check https://status.sentry.io."
77
+ }
78
+ }.freeze
79
+
80
+ # Look up guidance for an exception class name.
81
+ #
82
+ # @param exception_class [String] The exception class name (e.g., "Faraday::ResourceNotFound")
83
+ # @return [Hash, nil] A hash with +:message+ and +:action+ keys, or nil if unknown
84
+ def self.for(exception_class)
85
+ EXCEPTIONS[exception_class]
86
+ end
87
+
88
+ # Describe an HTTP status code.
89
+ #
90
+ # @param code [Integer] HTTP status code
91
+ # @return [String, nil] Description of the status code
92
+ def self.status_code_description(code)
93
+ STATUS_CODES[code]
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ask
4
+ module Sentry
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
data/lib/ask-sentry.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ask/sentry/version"
4
+ require_relative "ask/sentry/context"
5
+ require_relative "ask/sentry/client"
6
+ require_relative "ask/sentry/error_guide"
metadata ADDED
@@ -0,0 +1,176 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ask-sentry
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kaka Ruto
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ask-core
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ask-auth
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: faraday
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: faraday-retry
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.2'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.2'
68
+ - !ruby/object:Gem::Dependency
69
+ name: minitest
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '5.25'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '5.25'
82
+ - !ruby/object:Gem::Dependency
83
+ name: mocha
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.1'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.1'
96
+ - !ruby/object:Gem::Dependency
97
+ name: vcr
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '6.3'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '6.3'
110
+ - !ruby/object:Gem::Dependency
111
+ name: webmock
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.23'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.23'
124
+ - !ruby/object:Gem::Dependency
125
+ name: rake
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '13.0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '13.0'
138
+ description: Error context for agents via Sentry for the ask-rb ecosystem.
139
+ email:
140
+ - kaka@myrrlabs.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - CHANGELOG.md
146
+ - LICENSE
147
+ - README.md
148
+ - lib/ask-sentry.rb
149
+ - lib/ask/sentry/client.rb
150
+ - lib/ask/sentry/context.rb
151
+ - lib/ask/sentry/error_guide.rb
152
+ - lib/ask/sentry/version.rb
153
+ homepage: https://github.com/ask-rb/ask-sentry
154
+ licenses:
155
+ - MIT
156
+ metadata:
157
+ source_code_uri: https://github.com/ask-rb/ask-sentry
158
+ changelog_uri: https://github.com/ask-rb/ask-sentry/blob/main/CHANGELOG.md
159
+ rdoc_options: []
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '3.2'
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ requirements: []
173
+ rubygems_version: 4.0.3
174
+ specification_version: 4
175
+ summary: Sentry — error tracking via the Sentry API
176
+ test_files: []