naijacloud-argus 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: 245ee709a587c9f68b9eef5f35f5e2a27105e0e2e8a2c58c0c3906a5021b3faf
4
+ data.tar.gz: 68f0528cdd050cc668eb0e2263ef5bd875e6aad21012fc1e1fcb3e2a5f8a50e8
5
+ SHA512:
6
+ metadata.gz: 2ee64e8216a1b732fcaf87f1e2db53bfee3ee4ec012568a30eb53e9c70461eca5e312ca622bb25a38b0986712941bbf4e2e1c7db8e76a1df54dc24dafc52cee0
7
+ data.tar.gz: 50d4d3875834fa3523daed9638ab847be2eaa02defc8cbd33772d740945d671301bd150f971f21ffa07cf1c9bb379339de49a3e70b1561315a6c2491200c259c
data/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to `naijacloud-argus` are listed here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the gem uses
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-10-26
10
+
11
+ First release, implementing the Argus SDK contract `argus.sdk/1`.
12
+
13
+ ### Added
14
+
15
+ - `NaijaCloud::Argus.init`, with keywords or a block. Reads `ARGUS_DSN`,
16
+ `ARGUS_RELEASE` and `ARGUS_ENVIRONMENT`, then the `SENTRY_*` names. Without a
17
+ DSN every call is a no-op.
18
+ - **Errors:** `capture_exception` (with the `cause` chain and source context
19
+ lines), `capture_message`, `set_user`, `set_tag(s)`, `set_context`,
20
+ `add_breadcrumb`, `with_scope`, `before_send`, `before_breadcrumb`,
21
+ `excluded_exceptions`. Sent as gzipped Sentry envelopes.
22
+ - **Rails** (Railtie, no setup beyond `bundle add` and `ARGUS_DSN`): request
23
+ tracing named by route, unhandled exceptions, ActiveJob failures and spans, a
24
+ `Rails.error` subscriber, and optional `Rails.logger` forwarding
25
+ (`rails_logs`).
26
+ - **Rack middleware** `NaijaCloud::Argus::Rack` for Sinatra, Hanami, Roda,
27
+ Grape and plain Rack: server spans continuing W3C `traceparent`, and
28
+ unhandled exceptions with the request.
29
+ - **Outgoing `Net::HTTP`**: client spans, `traceparent` propagation and
30
+ breadcrumbs.
31
+ - **Logs, metrics and traces** over OTLP/HTTP JSON: `log.info` and the other
32
+ levels, a `::Logger`-compatible `NaijaCloud::Argus::Logger`,
33
+ `metrics.count` / `gauge` / `distribution`, `trace` and `start_span`.
34
+ - **Cron check-ins by monitor slug:** `cron.check_in` and `monitor`.
35
+ - **Feature flags:** `flags.on?`, `flags.variant` and `flags.all`, cached 30 s.
36
+ - **Transport:** one background thread and bounded queue per endpoint, retries
37
+ with backoff, `Retry-After` on 429, stops on a refused key, fork-safe, never
38
+ raises. Uncaught exceptions are reported and queues flushed at exit.
39
+ - **Privacy defaults on:** sensitive keys, card numbers, tokens and JWTs are
40
+ filtered; query strings, cookies and IP addresses are not sent.
41
+
42
+ [Unreleased]: https://github.com/naijacloud/argus-ruby/compare/v0.1.0...HEAD
43
+ [0.1.0]: https://github.com/naijacloud/argus-ruby/releases/tag/v0.1.0
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,93 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ Nothing to install. The gem has no runtime dependencies, and minitest and rake
6
+ ship with Ruby.
7
+
8
+ ```sh
9
+ rake test
10
+ ```
11
+
12
+ or, without bundler or rake at all:
13
+
14
+ ```sh
15
+ ruby -Ilib -Itest test/errors_test.rb
16
+ ```
17
+
18
+ ## Tests
19
+
20
+ The suite runs **offline**. `test/test_helper.rb` starts a small HTTP server on
21
+ `127.0.0.1` with an ephemeral port, built on raw `TCPServer` (webrick left the
22
+ standard library in Ruby 3.0). There is no WebMock and no VCR, and no test
23
+ makes an outbound connection.
24
+
25
+ ```ruby
26
+ @server.enqueue(status: 429, headers: { "Retry-After" => "7" })
27
+ @server.enqueue(status: 500)
28
+ ```
29
+
30
+ Unscripted requests get a 200. Gzipped bodies are decoded for you, and
31
+ `envelope(request)` / `event_from(request)` parse an error envelope.
32
+
33
+ Retry timing is asserted, not slept through: `capture_sleeps(client)` (or
34
+ `transport.sleeper = ->(s) { ... }`) records the waits instead of waiting.
35
+
36
+ **Rails.** `test/rails_test.rb` boots a minimal Rails app in a child process.
37
+ It is skipped when Rails is not installed, which keeps the default suite
38
+ dependency-free. To run it:
39
+
40
+ ```sh
41
+ gem install railties activejob
42
+ ruby -Ilib -Itest test/rails_test.rb
43
+ ```
44
+
45
+ CI runs it against Rails 7.1, 7.2 and 8.0.
46
+
47
+ **Contract test.** `rake contract` sends one of each signal to a real Argus
48
+ and checks every endpoint answered 2xx:
49
+
50
+ ```sh
51
+ ARGUS_CONTRACT_DSN=<dsn of a test source> rake contract
52
+ ```
53
+
54
+ It expects a cron monitor with slug `argus-ruby-contract`; without one, the
55
+ cron check-in's 404 is reported, not failed.
56
+
57
+ ## What to keep in mind when changing this gem
58
+
59
+ - **The contract is binding.** `nc-argus/spec/README.md` (`argus.sdk/1`) is the
60
+ document every Argus SDK implements. A behaviour change here is owed to the
61
+ others too. If the contract and ingest disagree, ingest wins and the contract
62
+ gets fixed.
63
+ - **Never raise into the app, never block it.** Public methods go through
64
+ `NaijaCloud::Argus.safely`; sending happens on the transport's threads.
65
+ - **Zero runtime dependencies.** See SECURITY.md.
66
+ - **Ruby 3.0 is the supported floor,** but keep the code 2.7-compatible: no
67
+ endless methods, no `Hash#except`, no pattern matching. And no keyword
68
+ arguments on a method that also takes an attributes hash: on Ruby 3 a
69
+ braceless `"key" => value` would be taken for keywords.
70
+
71
+ ## House style
72
+
73
+ Comments explain **why**: the decision, the failure it prevents, the trap it
74
+ avoids. `# frozen_string_literal: true` at the top of every file.
75
+
76
+ ## Releasing
77
+
78
+ 1. Update `lib/naijacloud/argus/version.rb`.
79
+ 2. Move the `Unreleased` changelog entries under `## [x.y.z] - YYYY-MM-DD` and
80
+ update the link definitions at the foot of the file.
81
+ 3. Tag and push: `git tag v<version> && git push origin v<version>`.
82
+
83
+ `.github/workflows/release.yml` runs CI, refuses a tag that disagrees with
84
+ `VERSION` or has no changelog section, builds and pushes the gem with RubyGems
85
+ trusted publishing, then creates the GitHub release.
86
+
87
+ ### One-time setup
88
+
89
+ - **rubygems.org → Settings → Trusted publishers → Create a pending trusted
90
+ publisher:** gem `naijacloud-argus`, owner `naijacloud`, repository
91
+ `argus-ruby`, workflow `release.yml`, environment `rubygems`.
92
+ - **GitHub → Settings → Environments → New environment `rubygems`.** Add
93
+ required reviewers to make a push wait for a human.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NaijaCloud
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,255 @@
1
+ <p align="center">
2
+ <a href="https://www.naijacloud.com/argus">
3
+ <img alt="Naijacloud Argus, Ruby SDK" src="https://raw.githubusercontent.com/naijacloud/argus-ruby/main/.github/assets/banner.png" width="100%">
4
+ </a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://rubygems.org/gems/naijacloud-argus"><img alt="gem" src="https://img.shields.io/badge/gem-naijacloud--argus-008751?style=flat-square&labelColor=0A0E0C"></a>
9
+ <img alt="ruby" src="https://img.shields.io/badge/ruby-%3E%3D_3.0-E0483F?style=flat-square&labelColor=0A0E0C">
10
+ <img alt="dependencies" src="https://img.shields.io/badge/dependencies-0-46C98A?style=flat-square&labelColor=0A0E0C">
11
+ <a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-8A988F?style=flat-square&labelColor=0A0E0C"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="#install">Install</a> ·
16
+ <a href="#rails">Rails</a> ·
17
+ <a href="#rack-sinatra-and-plain-ruby">Rack</a> ·
18
+ <a href="#errors">Errors</a> ·
19
+ <a href="#logs-metrics-and-traces">Logs, metrics, traces</a> ·
20
+ <a href="#cron-check-ins">Crons</a> ·
21
+ <a href="#feature-flags">Flags</a> ·
22
+ <a href="#privacy">Privacy</a> ·
23
+ <a href="#options">Options</a>
24
+ </p>
25
+
26
+ # naijacloud-argus
27
+
28
+ The official Ruby SDK for [Argus](https://www.naijacloud.com/argus),
29
+ Naijacloud's monitoring. One gem sends errors, logs, metrics, traces, cron
30
+ check-ins and feature-flag checks, with one key: your app's **DSN**.
31
+
32
+ It has no runtime dependencies (standard-library `net/http`, `json` and `zlib`
33
+ only), implements the Argus SDK contract **`argus.sdk/1`**, and works for apps
34
+ hosted anywhere, not only on Naijacloud.
35
+
36
+ **Already using `sentry-ruby`?** Keep it. Argus accepts it: point its `dsn` at
37
+ Argus and you're done. Switch to this gem when you want logs, metrics, cron
38
+ check-ins and flags through the same setup.
39
+
40
+ ## Install
41
+
42
+ ```sh
43
+ bundle add naijacloud-argus
44
+ ```
45
+
46
+ Ruby 3.0 or newer. Copy the DSN (your app's key) from the source in Argus. It
47
+ looks like `https://<key>@argus-in.naijacloud.com/<number>`.
48
+
49
+ ## Rails
50
+
51
+ ```sh
52
+ bundle add naijacloud-argus
53
+ ARGUS_DSN=https://…@argus-in.naijacloud.com/41 bin/rails server
54
+ ```
55
+
56
+ That's the whole setup. The gem's Railtie:
57
+
58
+ - **starts Argus** after your initializers, reading `ARGUS_DSN`,
59
+ `ARGUS_RELEASE` and `ARGUS_ENVIRONMENT` (falling back to `SENTRY_DSN`,
60
+ `SENTRY_RELEASE` and `SENTRY_ENVIRONMENT`). With no environment variable set,
61
+ the environment is `Rails.env` and the service name is your app's name;
62
+ - **traces every request**, named by its route (`GET /orders/:id`), and
63
+ continues a `traceparent` header from the caller;
64
+ - **reports unhandled exceptions** with the request they came from. A 404 or a
65
+ bad CSRF token is not reported;
66
+ - **reports ActiveJob failures** with the job's class, id and queue, and traces
67
+ each job. Your `retry_on` and `discard_on` still behave as before;
68
+ - **subscribes to `Rails.error`** (Rails 7.0+), so `Rails.error.report` and
69
+ `Rails.error.handle` reach Argus too;
70
+ - **traces outgoing `Net::HTTP` calls** (and Faraday, HTTParty and anything else
71
+ built on it) and adds a `traceparent` header to them.
72
+
73
+ Without a DSN it does nothing, so development and test need no changes. Apps
74
+ hosted on Naijacloud get these variables set when the Argus tab is on.
75
+
76
+ To change options, add an initializer. It runs before the Railtie's own start,
77
+ so it wins:
78
+
79
+ ```ruby
80
+ # config/initializers/argus.rb
81
+ NaijaCloud::Argus.init do |c|
82
+ c.release = ENV["GIT_SHA"]
83
+ c.traces_sample_rate = 0.2
84
+ c.rails_logs = true # also send Rails.logger lines to Argus Logs
85
+ end
86
+ ```
87
+
88
+ ## Rack, Sinatra and plain Ruby
89
+
90
+ ```ruby
91
+ # config.ru
92
+ require "naijacloud/argus"
93
+ NaijaCloud::Argus.init # reads ARGUS_DSN
94
+ use NaijaCloud::Argus::Rack
95
+ run App
96
+ ```
97
+
98
+ The middleware gives you the same request spans and error reports as on Rails,
99
+ for Sinatra, Hanami, Roda, Grape and plain Rack.
100
+
101
+ **In a script or a worker,** call `init` at the top. An exception that ends the
102
+ process is reported, and whatever is queued is sent before the process exits.
103
+
104
+ ```ruby
105
+ require "naijacloud/argus"
106
+ NaijaCloud::Argus.init(dsn: ENV["ARGUS_DSN"], release: "1.4.2")
107
+ ```
108
+
109
+ ## Errors
110
+
111
+ ```ruby
112
+ begin
113
+ charge_card(order)
114
+ rescue Paystack::Error => e
115
+ NaijaCloud::Argus.capture_exception(e, tags: { provider: "paystack" }, extra: { order_id: order.id })
116
+ raise
117
+ end
118
+
119
+ NaijaCloud::Argus.capture_message("Webhook signature mismatch", level: :warning)
120
+ NaijaCloud::Argus.set_user(id: current_user.id)
121
+ NaijaCloud::Argus.set_tag("region", "af-west")
122
+ NaijaCloud::Argus.add_breadcrumb(category: "cart", message: "coupon applied", data: { code: "NAIJA10" })
123
+ ```
124
+
125
+ - **Causes:** an exception's `cause` chain is sent too.
126
+ - **Duplicates:** the same exception object is sent once, however many layers
127
+ (Rack, `Rails.error`, ActiveJob) see it.
128
+ - **Per request:** `set_user`, tags and breadcrumbs set during a request (or a
129
+ job) stay with that request; they don't leak to the next one on the same
130
+ thread or to other threads.
131
+ - **`before_send`** lets you change an event (a Hash), or return `nil` to drop it.
132
+ - `capture_exception` returns the event id, or `nil` when nothing was sent.
133
+
134
+ ## Logs, metrics and traces
135
+
136
+ ```ruby
137
+ NaijaCloud::Argus.log.info("order placed", order_id: "ord_81", total: 18_500)
138
+ NaijaCloud::Argus.log.error("paystack timed out", attempt: 3)
139
+
140
+ NaijaCloud::Argus.metrics.count("orders.placed", 1, method: "card")
141
+ NaijaCloud::Argus.metrics.gauge("queue.depth", jobs.size)
142
+ NaijaCloud::Argus.metrics.distribution("checkout.ms", elapsed_ms, nil, "ms")
143
+
144
+ NaijaCloud::Argus.trace("charge card", provider: "paystack") do |span|
145
+ span.set_attribute("amount", order.total)
146
+ paystack.charge(order)
147
+ end
148
+ ```
149
+
150
+ - **Logs** are sent in batches every 5 seconds (or every 1,000 lines). A line
151
+ written inside a request carries that request's trace id.
152
+ - **A `::Logger`** that sends to Argus Logs, for any library that takes one:
153
+ `NaijaCloud::Argus::Logger.new(level: :info)`. On Rails 7.1+,
154
+ `Rails.logger.broadcast_to(NaijaCloud::Argus::Logger.new)` keeps your normal
155
+ log output and adds Argus (or set `rails_logs = true`).
156
+ - **Metrics** are added up in the process and sent every 10 seconds.
157
+ - **Spans** join the request or job they run in. `trace` returns the block's
158
+ value; an exception marks the span failed and is re-raised. For work that
159
+ doesn't fit a block, `span = NaijaCloud::Argus.start_span("upload")` and later
160
+ `span.finish` (or `span.finish(error)`).
161
+ - **Propagate a trace** through something the gem doesn't instrument (a queue
162
+ message, gRPC metadata) with `NaijaCloud::Argus.traceparent`.
163
+ - **Sample traces** with `traces_sample_rate` (0 to 1, default 1).
164
+
165
+ ## Cron check-ins
166
+
167
+ Create a cron monitor in Argus first, then report runs by its slug:
168
+
169
+ ```ruby
170
+ NaijaCloud::Argus.monitor("nightly-invoices") do
171
+ InvoiceRun.call
172
+ end
173
+
174
+ # or by hand:
175
+ NaijaCloud::Argus.cron.check_in("nightly-invoices", :start)
176
+ NaijaCloud::Argus.cron.check_in("nightly-invoices", :ok) # or :error, or an exit code
177
+ ```
178
+
179
+ `monitor` reports the start, then success or failure, and re-raises your job's
180
+ exception. An unknown slug is answered 404 by Argus and dropped.
181
+
182
+ ## Feature flags
183
+
184
+ ```ruby
185
+ if NaijaCloud::Argus.flags.on?("new-checkout", current_user.id)
186
+ # …
187
+ end
188
+ theme = NaijaCloud::Argus.flags.variant("theme", current_user.id, "light")
189
+ NaijaCloud::Argus.flags.all(current_user.id) # => {"new-checkout"=>"on", "theme"=>"dark"}
190
+ ```
191
+
192
+ - **Caching:** answers are cached for 30 seconds per user (and attributes).
193
+ - **Fallback:** if Argus can't be reached within 2 seconds, or the flag doesn't
194
+ exist, you get the fallback you passed.
195
+ - **Targeting attributes** go last: `on?("beta", user.id, false, plan: "pro")`.
196
+
197
+ ## Privacy
198
+
199
+ On by default:
200
+
201
+ - The values of keys such as `password`, `token`, `secret`, `authorization`,
202
+ `cookie`, `bvn` and `card` are replaced with `[Filtered]`, at any depth: in
203
+ extra, contexts, breadcrumbs, log and span attributes.
204
+ - Card numbers, bearer tokens, JWTs and `password=…` pairs are filtered inside
205
+ strings, including exception messages and log lines.
206
+ - Query strings are removed from URLs in requests, breadcrumbs and spans.
207
+ - Request bodies and cookies are never sent.
208
+ - The user's IP address is not sent unless you set `send_default_pii: true`.
209
+
210
+ Argus filters again on arrival.
211
+
212
+ ## Options
213
+
214
+ Pass them to `init` as keywords, or set them in its block.
215
+
216
+ | Option | Default | |
217
+ | -- | -- | -- |
218
+ | `dsn` | `ARGUS_DSN`, then `SENTRY_DSN` | Without one, nothing is sent |
219
+ | `release` | `ARGUS_RELEASE`, then `SENTRY_RELEASE` | Your app's version, like `1.4.2` or a git commit |
220
+ | `environment` | `ARGUS_ENVIRONMENT`, then `SENTRY_ENVIRONMENT`, else `production` (`Rails.env` on Rails) | |
221
+ | `service_name` | `ARGUS_SERVICE_NAME`, else `app` (the app's name on Rails) | Shown on logs, metrics and traces |
222
+ | `sample_rate` | `1.0` | Share of errors sent |
223
+ | `traces_sample_rate` | `1.0` | Share of traces sent |
224
+ | `send_default_pii` | `false` | Send the user's IP address |
225
+ | `max_breadcrumbs` | `100` | |
226
+ | `before_send` / `before_breadcrumb` | | Change or drop an event or crumb (return `nil`) |
227
+ | `excluded_exceptions` | 404-type Rails errors | Class names never reported |
228
+ | `project_root` | `Rails.root` on Rails | Frames under it are marked in-app |
229
+ | `context_lines` | `true` | Send the lines of source around in-app frames |
230
+ | `net_http` | `true` | Trace outgoing `Net::HTTP` calls |
231
+ | `trace_propagation` | `true` | Add `traceparent` to outgoing requests |
232
+ | `rails_logs` | `false` | Also send `Rails.logger` lines as logs |
233
+ | `capture_at_exit` | `true` | Report the exception that ends the process |
234
+ | `debug` | `false` | Print what the SDK does to `$stderr` (or `ARGUS_DEBUG=1`) |
235
+ | `enabled` | `true` | Turn the SDK off without removing it |
236
+
237
+ The gem never raises into your app and never blocks a request: everything is
238
+ sent from background threads, with retries and backoff. Call
239
+ `NaijaCloud::Argus.flush` before a short script exits if it calls `exit!`;
240
+ otherwise the exit hook sends what's queued. It is safe with forking servers
241
+ (Puma, Unicorn) and job runners (Sidekiq, Resque): each child process starts
242
+ its own sender.
243
+
244
+ ## Not in this version
245
+
246
+ These are planned, and not done yet:
247
+
248
+ - automatic spans for ActiveRecord queries, Redis and view rendering;
249
+ - trace propagation from a request into the jobs it enqueues;
250
+ - reporting an ActiveJob failure only after its retries are used up (every
251
+ failed attempt is reported today).
252
+
253
+ ## License
254
+
255
+ MIT
data/SECURITY.md ADDED
@@ -0,0 +1,60 @@
1
+ # Security
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Email **security@naijacloud.com**. Please do not open a public issue, and do not
6
+ post a proof of concept anywhere public before we have shipped a fix.
7
+
8
+ Include what you did, what happened, and the version of the gem. We acknowledge
9
+ within two business days (West Africa Time) and will tell you what we intend to
10
+ do and by when.
11
+
12
+ ## What the DSN is, and is not
13
+
14
+ The DSN's key is a **public, send-only** credential: it can add events to one
15
+ Argus source and read nothing. It is not a secret in the way an API key is, so
16
+ a leaked DSN is a spam risk for that source, not a data breach. Rotate it from
17
+ the source's settings if it is being abused.
18
+
19
+ Even so, the gem keeps it tidy: on a server it travels in a header
20
+ (`X-Sentry-Auth` or `Authorization: Bearer`), never in the URL, so it does not
21
+ end up in proxy access logs. `Dsn#inspect` and `Client#inspect` do not print it.
22
+
23
+ ## What the gem does with your users' data
24
+
25
+ The gem sits inside your app and sees its exceptions, requests and logs, so it
26
+ is built to send as little as it can:
27
+
28
+ 1. **Sensitive keys are filtered before anything leaves the process,** at any
29
+ depth: `password`, `token`, `secret`, `authorization`, `cookie`, `bvn`,
30
+ `card`, `cvv`, `session` and the rest of the list in the Argus SDK contract
31
+ (§7). Card numbers (Luhn-checked), bearer/basic tokens, JWTs and
32
+ `password=…` pairs are filtered inside strings.
33
+ 2. **Request bodies and cookies are never sent.** Request headers are an
34
+ allowlist (host, user agent, accept, referer, request id, content type), not
35
+ a denylist, so a header nobody thought of is not sent.
36
+ 3. **Query strings are removed** from every URL the gem records.
37
+ 4. **IP addresses are not sent** unless you set `send_default_pii: true`.
38
+ 5. **TLS is verified** (`VERIFY_PEER`, set explicitly) and **redirects are never
39
+ followed**: a followed redirect would resend the key to a host the response
40
+ chose.
41
+ 6. **Debug output** (`debug: true`) prints what the SDK does, never payloads or
42
+ headers. `Net::HTTP#set_debug_output` is never called.
43
+
44
+ Argus filters again on arrival; the gem does not rely on that.
45
+
46
+ ## Supply chain
47
+
48
+ The gem has **zero runtime dependencies**. Everything is standard library:
49
+ `net/http`, `openssl`, `json`, `zlib`, `securerandom`, `socket`, `uri`, and
50
+ `logger` only if you use `NaijaCloud::Argus::Logger`.
51
+
52
+ That is deliberate. This package runs in every process of the apps that use
53
+ it, so every third-party dependency would be another maintainer whose account
54
+ compromise becomes our customers' incident. Releases require MFA on the
55
+ RubyGems account (`rubygems_mfa_required`).
56
+
57
+ ## Supported versions
58
+
59
+ Security fixes are released for the latest minor version. Ruby 3.0 and newer
60
+ are supported.