chronos-ruby 0.9.0.pre.3 → 0.9.0.pre.4

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: a834300cdaf9acd0d75e625d6cc811c677bd8cf2f701aed885e0bbae417aaca0
4
- data.tar.gz: 1b2e992ee0c9428e25bac17a8cbe21ae0bc167ebb519b63ae9c2e1cdb3ec3cc7
3
+ metadata.gz: 84266b3c93fc92c15268d44e3625762f471c9cf99fa0523b6f5d883f846906e4
4
+ data.tar.gz: bf3d2c641bbb7f117a1c9c76519fa756057f72108d899cb64d86e2eeff305423
5
5
  SHA512:
6
- metadata.gz: 53be3a9634f8a47b9701897f4b6b58e1f0d023b536a2f6f4a7649f2d31344cb07f161e9f5d11c7636217194bdf31fe8181f5c6d1e916ef6049020f59b1ff2c4a
7
- data.tar.gz: 40b56150fed7170583f514552cd34894c98e6b8011c09f8a188af29accc5dfe36ab72b78375875e88059324025b7d82f7ef4cbb13b184a034b0bff22e7a38ca5
6
+ metadata.gz: 9b54a3aef38f706677794b39740558586d9c69f083a3c2b3f2dc6ea20e3b60f2fe84765eb61a44fe2f230a03c03dcb27047cdd7a1853b14fc805fcb914d7cfb8
7
+ data.tar.gz: 2f915f461e658f93269d35e52f6d728ff32ef90a4a6ac765a6b92194a1fc53b06ca5350b2bc34c8d84197bf2263d523ead9a62ada46edbd9ae46363d3de27e05
data/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes are documented here. The project follows Semantic Versioning
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.0.pre.4] - 2026-07-22
8
+
9
+ ### Added
10
+
11
+ - `Chronos.verify_integration` and `chronos:verify_integration` send a correlated synthetic exception and report credential, project, receiver, and receipt status as bounded JSON;
12
+ - strict integration-verification response contract v1, Rails task registration, failure classification, security limits, and end-to-end tests.
13
+
14
+ ### Changed
15
+
16
+ - version advanced to `0.9.0.pre.4` because `0.9.0.pre.3` had already been published before integration verification was added.
17
+
18
+ ### Fixed
19
+
20
+ - legacy dependency resolution pins `parallel` to Ruby 2.2-compatible `1.19.2` and the Sidekiq 5 smoke pins `rack-protection` to Ruby 2.5-compatible `2.2.4`.
21
+ - the Rails verification task now always depends on `environment`, even when Rails defines that Rake task after the Chronos Railtie hook runs.
22
+
7
23
  ## [0.9.0.pre.3] - 2026-07-21
8
24
 
9
25
  ### Changed
data/README.md CHANGED
@@ -33,7 +33,7 @@ See [Compatibility](docs/compatibility.md).
33
33
  The current public build is a pre-release. Add its exact version to the application's `Gemfile`:
34
34
 
35
35
  ```ruby
36
- gem "chronos-ruby", "0.9.0.pre.3"
36
+ gem "chronos-ruby", "0.9.0.pre.4"
37
37
  ```
38
38
 
39
39
  Install with a Bundler version compatible with the application. For the oldest supported runtime:
@@ -54,7 +54,7 @@ gem install chronos-ruby --pre
54
54
  Version 0.5 exposes Rails support explicitly, keeping Rails and ActiveSupport out of plain Ruby applications:
55
55
 
56
56
  ```ruby
57
- gem "chronos-ruby", "0.9.0.pre.3", :require => "chronos/rails"
57
+ gem "chronos-ruby", "0.9.0.pre.4", :require => "chronos/rails"
58
58
  ```
59
59
 
60
60
  Generate the initializer with:
@@ -84,6 +84,27 @@ end
84
84
 
85
85
  HTTPS verification is enabled by default. HTTP requires explicitly setting `ssl_verify = false` and should only be used with a local test server.
86
86
 
87
+ ## Verify the Chronos integration
88
+
89
+ After configuring the application, Rails projects can verify credentials and end-to-end ingestion with:
90
+
91
+ ```bash
92
+ bundle exec rake chronos:verify_integration
93
+ ```
94
+
95
+ The task sends one synthetic exception identified as an integration verification and prints one JSON object. It exits with status `0` only when Chronos confirms valid credentials and receipt of the correlated event; configuration, authentication, inactive-project, network, protocol, rate-limit, and receiver failures exit nonzero with safe guidance.
96
+
97
+ Plain Ruby Rakefiles can install the same task explicitly after loading their configuration:
98
+
99
+ ```ruby
100
+ require "chronos"
101
+ # Chronos.configure { |config| ... }
102
+ require "chronos/rake_tasks"
103
+ Chronos::RakeTasks.install
104
+ ```
105
+
106
+ Ruby code may call `result = Chronos.verify_integration`, inspect `result.success?`, and serialize `result.to_h` or `result.to_json`. The result contains only bounded contract fields; it never exposes `project_key`, raw server responses, stack traces, source paths, or receiver internals. See [Integration verification](docs/modules/integration-verification.md).
107
+
87
108
  ## Automatic capture
88
109
 
89
110
  Rack applications can capture unhandled exceptions automatically and preserve the application error semantics:
@@ -201,7 +222,7 @@ Version `0.6.0.pre.1` adds optional Sidekiq 4/5 middleware:
201
222
 
202
223
  ```ruby
203
224
  gem "sidekiq", "~> 5.0"
204
- gem "chronos-ruby", "0.9.0.pre.3", :require => "chronos/sidekiq"
225
+ gem "chronos-ruby", "0.9.0.pre.4", :require => "chronos/sidekiq"
205
226
  ```
206
227
 
207
228
  The client middleware propagates only trace/request identifiers in a versioned Sidekiq-envelope field and never changes worker arguments. The server records class, queue, JID, retry count, duration, calculable queue latency, bounded arguments/tags, status, and error class. Values pass through the shared sanitizer before delivery. Failed jobs are notified once and the original exception is re-raised. See [Sidekiq 4/5 legacy integration](docs/modules/sidekiq-legacy.md).
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://chronos.example/schemas/integration-verification-response-v1.schema.json",
4
+ "title": "Chronos integration verification response v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schema_version",
9
+ "success",
10
+ "status",
11
+ "verification_id",
12
+ "credentials_valid",
13
+ "event_received",
14
+ "event",
15
+ "project",
16
+ "receiver",
17
+ "error"
18
+ ],
19
+ "properties": {
20
+ "schema_version": {"const": "1.0"},
21
+ "success": {"type": "boolean"},
22
+ "status": {
23
+ "enum": [
24
+ "accepted",
25
+ "invalid_credentials",
26
+ "project_inactive",
27
+ "receiver_unavailable",
28
+ "receiver_internal_error",
29
+ "request_rejected",
30
+ "rate_limited"
31
+ ]
32
+ },
33
+ "verification_id": {"type": "string", "minLength": 1, "maxLength": 128},
34
+ "credentials_valid": {"type": ["boolean", "null"]},
35
+ "event_received": {"type": "boolean"},
36
+ "event": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "required": ["id"],
40
+ "properties": {
41
+ "id": {"type": ["string", "null"], "maxLength": 128}
42
+ }
43
+ },
44
+ "project": {
45
+ "type": ["object", "null"],
46
+ "additionalProperties": false,
47
+ "required": ["id", "name", "status", "environment"],
48
+ "properties": {
49
+ "id": {"type": ["string", "null"], "maxLength": 128},
50
+ "name": {"type": ["string", "null"], "maxLength": 128},
51
+ "status": {"type": ["string", "null"], "maxLength": 32},
52
+ "environment": {"type": ["string", "null"], "maxLength": 128}
53
+ }
54
+ },
55
+ "receiver": {
56
+ "type": ["object", "null"],
57
+ "additionalProperties": false,
58
+ "required": ["name", "status", "received_at"],
59
+ "properties": {
60
+ "name": {"type": ["string", "null"], "maxLength": 64},
61
+ "status": {"type": ["string", "null"], "maxLength": 32},
62
+ "received_at": {"type": ["string", "null"], "maxLength": 64}
63
+ }
64
+ },
65
+ "error": {
66
+ "type": ["object", "null"],
67
+ "additionalProperties": false,
68
+ "required": ["code", "message", "guidance"],
69
+ "properties": {
70
+ "code": {"type": "string", "maxLength": 64},
71
+ "message": {"type": "string", "maxLength": 512},
72
+ "guidance": {"type": "string", "maxLength": 512}
73
+ }
74
+ }
75
+ }
76
+ }
@@ -48,6 +48,7 @@ Version 0.9 emits exceptions, cache telemetry, dependency/deploy events, and agg
48
48
  | Rails, web server, database adapter, Sidekiq, release | Included when safely detectable/configured | Loaded constants/specs and `app_version` |
49
49
  | Event release, revision, deploy ID, environment, service, region, instance | Present as bounded correlation; values optional | Explicit immutable configuration or normalized deploy payload |
50
50
  | Deploy environment, revision, version, repository, actor, deploy ID, service, region, instance | Explicit synchronous deploy API | Application/deployment integration arguments |
51
+ | Integration verification ID, fixed test marker, synthetic exception class/message, and receipt correlation | Only when `Chronos.verify_integration` or its Rake task is invoked | Locally generated bounded values |
51
52
 
52
53
  The gem never collects request bodies, response bodies, raw query strings, cookies, HTTP authorization headers, environment variables in bulk, Git state, source code, raw SQL, SQL bind values, database rows, raw cache keys/values, mail bodies/recipients, Active Job arguments, gem paths, or lockfile contents. Active Job IDs, Sidekiq JIDs/arguments, loaded gem names/versions, and deploy fields are documented integration data.
53
54
 
@@ -55,4 +56,6 @@ APM dimensions never include user ID, job ID, raw URL, exception message, bind v
55
56
 
56
57
  The secret `project_key` is an authentication header and is excluded from the JSON payload and logger diagnostics. The envelope field named `project_key` contains the public `project_id` required by the current v1 server contract.
57
58
 
59
+ The integration check uses the fixed class `Chronos::IntegrationVerificationError`, tag/fingerprint `chronos-integration-verification`, and `context.integration_verification.test: true`. Its returned object allowlists only project identity/status/environment, receiver name/status/receipt time, correlation IDs, booleans, and safe guidance. Raw response bodies and Chronos implementation details are discarded.
60
+
58
61
  See [Privacy and LGPD](privacy-lgpd.md) for redaction rules and the payload audit procedure.
@@ -0,0 +1,65 @@
1
+ # Integration verification
2
+
3
+ `Chronos.verify_integration` performs an explicit end-to-end check of configuration, credentials, receiver availability, and ingestion acknowledgement. Rails registers `chronos:verify_integration` automatically through the Railtie. The command prints exactly one JSON object and exits nonzero unless verification succeeds.
4
+
5
+ ## Flow and ownership
6
+
7
+ `Chronos::Application::VerifyIntegration` creates one normal v1 exception envelope, delivers it synchronously through `DeliveryPipeline`, and validates the response. `IntegrationVerificationResult` exposes the immutable, bounded public outcome. `RakeTasks` only loads the application environment, calls the facade, prints JSON, and selects the exit status.
8
+
9
+ The synthetic event is recognizable without changing the event protocol:
10
+
11
+ ```json
12
+ {
13
+ "event_type": "exception",
14
+ "payload": {
15
+ "exception": {"class": "Chronos::IntegrationVerificationError"},
16
+ "tags": ["chronos-integration-verification"],
17
+ "fingerprint": "chronos-integration-verification"
18
+ },
19
+ "context": {
20
+ "integration_verification": {
21
+ "schema_version": "1.0",
22
+ "verification_id": "generated-uuid",
23
+ "kind": "integration_verification",
24
+ "test": true
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ Chronos must authenticate before acknowledging the event and must correlate both `verification_id` and the envelope event ID. A `2xx` response alone is insufficient. The accepted response must conform exactly to [`integration-verification-response-v1.schema.json`](../../contracts/integration-verification-response-v1.schema.json):
31
+
32
+ ```json
33
+ {
34
+ "schema_version": "1.0",
35
+ "success": true,
36
+ "status": "accepted",
37
+ "verification_id": "generated-uuid",
38
+ "credentials_valid": true,
39
+ "event_received": true,
40
+ "event": {"id": "event-uuid"},
41
+ "project": {"id": "project-id", "name": "Project", "status": "active", "environment": "production"},
42
+ "receiver": {"name": "chronos", "status": "operational", "received_at": "2026-07-22T12:00:00Z"},
43
+ "error": null
44
+ }
45
+ ```
46
+
47
+ The client rejects missing, mismatched, or additional fields. It copies only the allowlisted project and receiver values and never returns the raw body.
48
+
49
+ ## Result and failure classification
50
+
51
+ The Ruby result supports `success?`, `to_h`, and `to_json`. Its status is `verified` only after the correlated acknowledgement. Failures use `configuration_invalid`, `invalid_credentials`, `project_inactive`, `receiver_unavailable`, `receiver_internal_error`, `rate_limited`, `request_rejected`, `invalid_response`, or `verification_failed`.
52
+
53
+ - `401` and untrusted `403` responses become `invalid_credentials` with instructions to create an active project API key and verify the configured identifiers.
54
+ - A contractual authenticated `403` response may become `project_inactive`.
55
+ - network errors, timeouts, an open circuit, and `502`/`503`/`504` become `receiver_unavailable`.
56
+ - other `5xx` responses become `receiver_internal_error`.
57
+ - malformed or uncorrelated success responses become `invalid_response`.
58
+
59
+ Failure output uses local messages and guidance. Server exception messages, stack traces, SQL, paths, classes, credentials, response headers, and architecture details are never copied.
60
+
61
+ ## Usage
62
+
63
+ In Rails, configure Chronos normally and run `bundle exec rake chronos:verify_integration`. In plain Ruby, require `chronos/rake_tasks` and call `Chronos::RakeTasks.install` from the Rakefile. Programmatic callers can use `Chronos.verify_integration` directly.
64
+
65
+ Verification is an explicit synchronous diagnostic operation. It bypasses sampling and ignore rules so an operator-requested check cannot silently disappear, but it still uses the configured bounded retry, timeout, TLS, circuit, serializer, and transport protections. The receiver should record it as a verification/audit receipt rather than a production application incident.
@@ -4,7 +4,7 @@ Version `0.6.0.pre.1` starts the legacy jobs line with optional Sidekiq 4 and 5
4
4
 
5
5
  ```ruby
6
6
  gem "sidekiq", "~> 5.0"
7
- gem "chronos-ruby", "0.9.0.pre.3", :require => "chronos/sidekiq"
7
+ gem "chronos-ruby", "0.9.0.pre.4", :require => "chronos/sidekiq"
8
8
  ```
9
9
 
10
10
  `chronos/sidekiq` installs middleware through the public `configure_client` and `configure_server` APIs. It does nothing when Sidekiq is unavailable, and the core gem never requires Sidekiq. Installation adds no Chronos thread or Redis/database connection per job; delivery continues through the agent's existing fixed worker pool.
data/docs/performance.md CHANGED
@@ -29,7 +29,7 @@ Current controls:
29
29
 
30
30
  Run the scripts under `benchmarks/` and record Ruby version, operating system, CPU, warmup, iteration count, median, and dispersion before publishing results. `benchmarks/filtering.rb` measures privacy filtering, `benchmarks/retry_backlog.rb` measures fixed-memory outage behavior, `benchmarks/request_overhead.rb` compares Rack-protocol calls, and `benchmarks/rails_notifications.rb` isolates subscriber normalization overhead.
31
31
 
32
- ## Version 0.9.0.pre.3 release gates
32
+ ## Version 0.9.0.pre.4 release gates
33
33
 
34
34
  `benchmarks/comparative.rb` compares the same successful Rack fixture without and with Chronos instrumentation. It performs configurable warmup, at least three samples, and reports median plus median absolute deviation. `benchmarks/fake_endpoint_load.rb` sends asynchronous exception events to a local TCP endpoint, verifies the v1 schema marker, ensures the secret key is absent from every payload, and fails on loss, rejection, invalid payload, or timeout.
35
35
 
data/docs/protocol-v1.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Protocol v1 stability
2
2
 
3
- The schemas under `contracts/` are the source of truth for protocol v1. Version `0.9.0.pre.3` keeps `schema_version: "1.0"` and treats every required field, enum value, privacy exclusion, and maximum as a compatibility contract.
3
+ The schemas under `contracts/` are the source of truth for protocol v1. Version `0.9.0.pre.4` keeps `schema_version: "1.0"` and treats every required field, enum value, privacy exclusion, and maximum as a compatibility contract.
4
4
 
5
5
  Compatible changes may add optional bounded fields or new event types accepted by the server. Removing or renaming a field, changing its type/meaning, weakening a bound, or making an optional field required needs a new protocol major schema. Authentication remains outside the JSON payload. Contract tests and `script/verify_docs` must pass before a release.
6
+
7
+ The explicit integration check uses the normal exception envelope and identifies itself through `context.integration_verification`. Its receiver acknowledgement is governed separately by [`integration-verification-response-v1.schema.json`](../contracts/integration-verification-response-v1.schema.json). A successful HTTP status without a complete, correlated response is not proof of authentication or ingestion.
@@ -1,8 +1,8 @@
1
1
  # Version 1.0 readiness
2
2
 
3
- Version `0.9.0.pre.3` is a hardening release, not the stable release. The local suite, lint, documentation verifier, build, load test, and comparative benchmark are required evidence. The release can advance to `1.0.0` only after the GitHub Actions matrix is green for every declared legacy Ruby/framework/job combination.
3
+ Version `0.9.0.pre.4` is a hardening release, not the stable release. The local suite, lint, documentation verifier, build, load test, and comparative benchmark are required evidence. The release can advance to `1.0.0` only after the GitHub Actions matrix is green for every declared legacy Ruby/framework/job combination.
4
4
 
5
- | Gate | State in pre.2 |
5
+ | Gate | State in pre.4 |
6
6
  |---|---|
7
7
  | Ruby pure, Rack, Rails 4.2/5.2 | Implemented; external legacy matrix must pass |
8
8
  | Sidekiq 4/5 real gems | Dedicated Docker matrix added; must pass |
@@ -1,6 +1,6 @@
1
- # Security review for 0.9.0.pre.3
1
+ # Security review for 0.9.0.pre.4
2
2
 
3
- Review date: 2026-07-21. Scope: capture, serialization, transport, remote configuration, framework/job integrations, release workflow, examples, and fixtures.
3
+ Review date: 2026-07-22. Scope: capture, serialization, transport, integration verification, remote configuration, framework/job integrations, release workflow, examples, and fixtures.
4
4
 
5
5
  Verified by contracts and implementation review:
6
6
 
@@ -12,5 +12,6 @@ Verified by contracts and implementation review:
12
12
  - integrations contain agent failures and do not collect bodies, authorization, raw SQL/binds, mail content, or raw cache keys;
13
13
  - Active Job propagation uses a namespaced v1 field containing only bounded trace/request identifiers and does not alter job arguments;
14
14
  - fixture privacy is enforced by contract tests and dependency advisories are checked by the security workflow.
15
+ - integration verification accepts only a strict correlated response and never exposes raw receiver bodies, credentials, stack traces, paths, SQL, or internal architecture.
15
16
 
16
17
  Residual risks: supported Ruby/Rails versions are end-of-life; in-memory backlog is lost at exit; application filters/ignore rules execute application code; project identifiers and documented job IDs may be personal data in some deployments; package signing is not enabled because no trusted certificate/key lifecycle exists. Release artifacts should use protected environments and published SHA-256 checksums until signing can be operated safely.
@@ -12,6 +12,12 @@ The agent may be unconfigured, disabled, ignored in the current environment, una
12
12
 
13
13
  Check DNS, TLS certificates, credentials, HTTP status, proxy configuration, and timeout values. The resilience layer retries only network errors, HTTP `408`, `429`, and `5xx` responses. Inspect `agent.diagnostics` when constructing an agent directly to see retry state, backlog usage, and the circuit state.
14
14
 
15
+ ## `chronos:verify_integration` fails
16
+
17
+ Read the single JSON object printed by the task and use `status` and `error.guidance`. `invalid_credentials` means an active project API key must be created or the configured `project_id`/`project_key` corrected. `project_inactive` means authentication succeeded but the selected project must be activated. `receiver_unavailable` covers DNS, TLS, network, timeout, circuit-open, and gateway/service-unavailable failures. `receiver_internal_error` means Chronos reached its own safe internal-error boundary. `invalid_response` means the receiver did not implement the correlated response v1 contract. Every failure exits nonzero and deliberately omits raw receiver messages and implementation details.
18
+
19
+ If Rails does not list the task, require `chronos/rails` and confirm the application initializer loads. A `not_configured` result means the current Rake process did not execute `Chronos.configure`; update to a release containing the Rails environment prerequisite fix and confirm the variables are exported into that process. In plain Ruby, require `chronos/rake_tasks` and call `Chronos::RakeTasks.install` from the Rakefile after loading configuration.
20
+
15
21
  ## Rack exception is not captured
16
22
 
17
23
  Confirm that `Chronos.configure` runs before the middleware handles requests and that the middleware wraps the application component that raises. Version 0.5 captures exceptions raised by the initial downstream Rack call; an exception raised later while a server enumerates a streaming response body is outside this release. The original exception is always re-raised, so the server log should still show it.
@@ -22,6 +22,7 @@ module Chronos
22
22
  class NetHttpTransport
23
23
  EVENT_PATH = "/api/v1/events".freeze
24
24
  REMOTE_CONFIGURATION_HEADER = "X-Chronos-Remote-Configuration".freeze
25
+ RESPONSE_BODY_MAX_BYTES = 8192
25
26
 
26
27
  def initialize(config, logger = nil)
27
28
  @config = config
@@ -71,7 +72,11 @@ module Chronos
71
72
  request["Idempotency-Key"] = event.event_id
72
73
  request.body = request_body(event.body)
73
74
  request["Content-Encoding"] = "gzip" if @config.gzip
74
- http.start { |connection| connection.request(request) }
75
+ http.start do |connection|
76
+ connection.request(request) do |response|
77
+ read_bounded_response(response)
78
+ end
79
+ end
75
80
  end
76
81
 
77
82
  def endpoint_uri
@@ -101,7 +106,7 @@ module Chronos
101
106
 
102
107
  def classify(response)
103
108
  code = response.code.to_i
104
- options = {:status_code => code}
109
+ options = {:status_code => code, :response => parse_response(response)}
105
110
  if code >= 200 && code < 300
106
111
  options[:remote_configuration] = parse_remote_configuration(response)
107
112
  return Ports::TransportResult.new(:success, options)
@@ -116,6 +121,35 @@ module Chronos
116
121
  Ports::TransportResult.new(:client_error, options)
117
122
  end
118
123
 
124
+ def read_bounded_response(response)
125
+ body = ""
126
+ overflow = false
127
+ response.read_body do |chunk|
128
+ next if overflow
129
+
130
+ remaining = RESPONSE_BODY_MAX_BYTES - body.bytesize
131
+ if chunk.bytesize > remaining
132
+ overflow = true
133
+ else
134
+ body << chunk
135
+ end
136
+ end
137
+ response.instance_variable_set(:@chronos_response_body, overflow ? nil : body)
138
+ end
139
+
140
+ def parse_response(response)
141
+ content_type = response["Content-Type"].to_s.split(";", 2).first
142
+ return nil unless content_type == "application/json"
143
+
144
+ body = response.instance_variable_get(:@chronos_response_body)
145
+ return nil if body.nil? || body.empty?
146
+
147
+ parsed = JSON.parse(body)
148
+ parsed.is_a?(Hash) ? parsed : nil
149
+ rescue JSON::ParserError, EncodingError
150
+ nil
151
+ end
152
+
119
153
  def parse_remote_configuration(response)
120
154
  return nil unless @config.remote_configuration
121
155
 
data/lib/chronos/agent.rb CHANGED
@@ -50,6 +50,24 @@ module Chronos
50
50
  @capture.call_sync(exception, context_for_capture(context))
51
51
  end
52
52
 
53
+ def verify_integration
54
+ @verification.call
55
+ rescue StandardError => error
56
+ @logger.warn("Chronos integration verification failed: #{error.class}")
57
+ Core::IntegrationVerificationResult.new(
58
+ :success => false,
59
+ :status => "verification_failed",
60
+ :credentials_valid => nil,
61
+ :event => {"id" => nil, "received" => false},
62
+ :receiver => {"name" => "chronos", "status" => "not_checked", "received_at" => nil},
63
+ :error => {
64
+ "code" => "verification_failed",
65
+ "message" => "Chronos integration verification failed locally.",
66
+ "guidance" => "Review the Chronos configuration and retry."
67
+ }
68
+ )
69
+ end
70
+
53
71
  def ignore_if(&block)
54
72
  @ignore_policy.add(&block)
55
73
  end
@@ -202,6 +220,9 @@ module Chronos
202
220
  def initialize_observability(options)
203
221
  @dependency_reporter = options[:dependency_reporter] || Application::DependencyReporter.new(@config)
204
222
  @deploy_normalizer = options[:deploy_normalizer] || Core::DeployNormalizer.new(@config)
223
+ @verification = options[:verification] || Application::VerifyIntegration.new(
224
+ @config, @delivery_pipeline, @logger
225
+ )
205
226
  end
206
227
 
207
228
  def build_context_store(strategy)
@@ -42,13 +42,16 @@ module Chronos
42
42
  end
43
43
 
44
44
  def deliver_sync(event)
45
+ deliver_sync_result(event).success?
46
+ end
47
+
48
+ def deliver_sync_result(event)
45
49
  record_pre_delivery(event)
46
- result = deliver_with_backlog(event)
47
- result && result.success?
50
+ deliver_with_backlog(event)
48
51
  rescue StandardError => error
49
52
  diagnose(error)
50
53
  store_in_backlog(event)
51
- false
54
+ Ports::TransportResult.new(:network_error, :error => error.class.name)
52
55
  end
53
56
 
54
57
  # WorkerPool delivery entry point. Events were counted when accepted into the queue.
@@ -0,0 +1,262 @@
1
+ require "securerandom"
2
+
3
+ module Chronos
4
+ module Application
5
+ # Sends and verifies one synthetic exception against the configured Chronos receiver.
6
+ #
7
+ # @responsibility Build an identified test notice, deliver it synchronously, and validate its acknowledgement.
8
+ # @motivation Verify credentials and end-to-end ingestion without mistaking an empty 2xx for confirmation.
9
+ # @limits It exposes only allowlisted project/receiver fields and never returns raw server responses.
10
+ # @collaborators NoticeBuilder, PayloadSerializer, DeliveryPipeline, and IntegrationVerificationResult.
11
+ # @thread_safety Calls allocate independent IDs and immutable results; collaborators synchronize delivery.
12
+ # @compatibility Ruby 2.2.10 through Ruby 2.6; independent of Rails.
13
+ # @example
14
+ # result = verifier.call
15
+ # result.success? #=> true or false
16
+ # @errors Network, protocol, configuration, and receiver failures become structured results.
17
+ # @performance Performs one bounded synchronous verification plus configured bounded retries.
18
+ class VerifyIntegration
19
+ SCHEMA_VERSION = "1.0".freeze
20
+ VERIFICATION_KIND = "integration_verification".freeze
21
+ VERIFICATION_TAG = "chronos-integration-verification".freeze
22
+
23
+ def initialize(config, delivery_pipeline, logger = nil, options = {})
24
+ @config = config
25
+ @delivery_pipeline = delivery_pipeline
26
+ @logger = logger || Internal::SafeLogger.new(config.logger)
27
+ @uuid_generator = options[:uuid_generator] || proc { SecureRandom.uuid }
28
+ @notice_builder = options[:notice_builder] || Core::NoticeBuilder.new(config)
29
+ @serializer = options[:serializer] || Core::PayloadSerializer.new(
30
+ config,
31
+ nil,
32
+ :max_payload_size => proc { @delivery_pipeline.max_payload_size }
33
+ )
34
+ end
35
+
36
+ def call
37
+ verification_id = bounded(@uuid_generator.call, 128)
38
+ return local_failure("configuration_invalid", verification_id, configuration_guidance) unless configured?
39
+
40
+ event = build_event(verification_id)
41
+ transport_result = @delivery_pipeline.deliver_sync_result(event)
42
+ classify(transport_result, verification_id, event.event_id)
43
+ rescue StandardError => error
44
+ @logger.warn("Chronos integration verification failed: #{error.class}")
45
+ local_failure("verification_failed", verification_id, "Review the Chronos configuration and retry.")
46
+ end
47
+
48
+ private
49
+
50
+ def configured?
51
+ !@config.project_id.to_s.empty? && !@config.project_key.to_s.empty? && !@config.host.to_s.empty?
52
+ end
53
+
54
+ def build_event(verification_id)
55
+ marker = {
56
+ "schema_version" => SCHEMA_VERSION,
57
+ "verification_id" => verification_id,
58
+ "kind" => VERIFICATION_KIND,
59
+ "test" => true
60
+ }
61
+ notice = @notice_builder.call(
62
+ IntegrationVerificationError.new("Chronos integration verification test"),
63
+ :severity => "info",
64
+ :context => {"integration_verification" => marker},
65
+ :tags => [VERIFICATION_TAG],
66
+ :fingerprint => VERIFICATION_TAG
67
+ )
68
+ @serializer.call(notice)
69
+ end
70
+
71
+ def classify(result, verification_id, event_id)
72
+ return classify_success(result.response, verification_id, event_id) if result.success?
73
+ if inactive_response?(result, verification_id, event_id)
74
+ return project_inactive(result.response, verification_id, event_id)
75
+ end
76
+ return invalid_credentials(verification_id, event_id) if [401, 403].include?(result.status_code)
77
+ return rate_limited(verification_id, event_id) if result.status == :rate_limited
78
+ return receiver_unavailable(verification_id, event_id) if unavailable?(result)
79
+ return receiver_internal_error(verification_id, event_id) if result.status == :server_error
80
+
81
+ request_rejected(verification_id, event_id)
82
+ end
83
+
84
+ def classify_success(response, verification_id, event_id)
85
+ unless valid_acknowledgement?(response, verification_id, event_id)
86
+ return failure("invalid_response", verification_id, event_id,
87
+ :receiver_status => "reachable",
88
+ :message => "Chronos returned a response outside the verification contract.",
89
+ :guidance => "Update Chronos to the integration verification response v1 contract.")
90
+ end
91
+
92
+ Core::IntegrationVerificationResult.new(
93
+ :success => true,
94
+ :status => "verified",
95
+ :verification_id => verification_id,
96
+ :credentials_valid => true,
97
+ :event => {"id" => event_id, "received" => true},
98
+ :project => safe_project(response["project"]),
99
+ :receiver => safe_receiver(response["receiver"]),
100
+ :error => nil
101
+ )
102
+ end
103
+
104
+ def valid_acknowledgement?(response, verification_id, event_id)
105
+ valid_response_structure?(response) &&
106
+ acknowledgement_matches?(response, verification_id, event_id) &&
107
+ active_project?(response["project"]) && operational_receiver?(response["receiver"])
108
+ end
109
+
110
+ def valid_response_structure?(response)
111
+ exact_keys?(response, %w(
112
+ schema_version success status verification_id credentials_valid event_received
113
+ event project receiver error
114
+ )) &&
115
+ exact_keys?(response["event"], %w(id)) &&
116
+ exact_keys?(response["project"], %w(id name status environment)) &&
117
+ exact_keys?(response["receiver"], %w(name status received_at))
118
+ end
119
+
120
+ def acknowledgement_matches?(response, verification_id, event_id)
121
+ response["schema_version"] == SCHEMA_VERSION && response["verification_id"] == verification_id &&
122
+ response["status"] == "accepted" && response["success"] == true &&
123
+ response["credentials_valid"] == true && response["event_received"] == true &&
124
+ hash_value(response["event"])["id"] == event_id && response["error"].nil?
125
+ end
126
+
127
+ def active_project?(project)
128
+ hash_value(project)["id"] == @config.project_id.to_s && hash_value(project)["status"] == "active"
129
+ end
130
+
131
+ def operational_receiver?(receiver)
132
+ hash_value(receiver)["status"] == "operational"
133
+ end
134
+
135
+ def inactive_response?(result, verification_id, event_id)
136
+ response = result.response
137
+ result.status_code == 403 && valid_response_structure?(response) &&
138
+ inactive_state?(response) && inactive_correlation?(response, verification_id, event_id)
139
+ end
140
+
141
+ def inactive_state?(response)
142
+ response["schema_version"] == SCHEMA_VERSION && response["success"] == false &&
143
+ response["status"] == "project_inactive" && response["credentials_valid"] == true &&
144
+ response["event_received"] == false && hash_value(response["project"])["status"] == "inactive" &&
145
+ valid_error?(response["error"])
146
+ end
147
+
148
+ def inactive_correlation?(response, verification_id, event_id)
149
+ response["verification_id"] == verification_id && hash_value(response["event"])["id"] == event_id &&
150
+ hash_value(response["project"])["id"] == @config.project_id.to_s
151
+ end
152
+
153
+ def valid_error?(error)
154
+ exact_keys?(error, %w(code message guidance)) && error["code"] == "project_inactive"
155
+ end
156
+
157
+ def project_inactive(response, verification_id, event_id)
158
+ failure("project_inactive", verification_id, event_id,
159
+ :credentials_valid => true, :receiver_status => "reachable",
160
+ :message => "The Chronos project is inactive and did not accept the verification event.",
161
+ :guidance => "Activate the project in Chronos or select an active project, then retry.",
162
+ :project => safe_project(response["project"]))
163
+ end
164
+
165
+ def invalid_credentials(verification_id, event_id)
166
+ failure("invalid_credentials", verification_id, event_id,
167
+ :credentials_valid => false, :receiver_status => "reachable",
168
+ :message => "Chronos rejected the project credentials.",
169
+ :guidance => "Create an active project API key, then confirm project_id and project_key.")
170
+ end
171
+
172
+ def rate_limited(verification_id, event_id)
173
+ failure("rate_limited", verification_id, event_id,
174
+ :receiver_status => "reachable",
175
+ :message => "Chronos temporarily rate limited the verification request.",
176
+ :guidance => "Wait before retrying and review the project ingestion limits.")
177
+ end
178
+
179
+ def receiver_internal_error(verification_id, event_id)
180
+ failure("receiver_internal_error", verification_id, event_id,
181
+ :receiver_status => "error",
182
+ :message => "Chronos encountered an internal error while processing the verification.",
183
+ :guidance => "Retry later or contact the Chronos operator with the verification_id.")
184
+ end
185
+
186
+ def receiver_unavailable(verification_id, event_id)
187
+ failure("receiver_unavailable", verification_id, event_id,
188
+ :receiver_status => "unavailable",
189
+ :message => "The Chronos receiver is unavailable or could not be reached.",
190
+ :guidance => "Check the host, DNS, TLS, network access, and Chronos service status.")
191
+ end
192
+
193
+ def request_rejected(verification_id, event_id)
194
+ failure("request_rejected", verification_id, event_id,
195
+ :receiver_status => "reachable",
196
+ :message => "Chronos rejected the integration verification request.",
197
+ :guidance => "Confirm that the gem and Chronos support the verification v1 contract.")
198
+ end
199
+
200
+ def unavailable?(result)
201
+ [:network_error, :request_timeout, :circuit_open].include?(result.status) ||
202
+ [502, 503, 504].include?(result.status_code)
203
+ end
204
+
205
+ def failure(status, verification_id, event_id, options = {})
206
+ Core::IntegrationVerificationResult.new(
207
+ :success => false,
208
+ :status => status,
209
+ :verification_id => verification_id,
210
+ :credentials_valid => options[:credentials_valid],
211
+ :event => {"id" => event_id, "received" => false},
212
+ :project => options[:project],
213
+ :receiver => {"name" => "chronos", "status" => options[:receiver_status], "received_at" => nil},
214
+ :error => {"code" => status, "message" => options[:message], "guidance" => options[:guidance]}
215
+ )
216
+ end
217
+
218
+ def local_failure(status, verification_id, guidance)
219
+ failure(status, verification_id, nil,
220
+ :receiver_status => "not_checked",
221
+ :message => "Chronos integration verification could not be started.",
222
+ :guidance => guidance)
223
+ end
224
+
225
+ def configuration_guidance
226
+ "Configure a non-empty project_id, project_key, and HTTPS host before running verification."
227
+ end
228
+
229
+ def safe_project(value)
230
+ safe_fields(value, "id" => 128, "name" => 128, "status" => 32, "environment" => 128)
231
+ end
232
+
233
+ def safe_receiver(value)
234
+ safe_fields(value, "name" => 64, "status" => 32, "received_at" => 64)
235
+ end
236
+
237
+ def safe_fields(value, fields)
238
+ source = hash_value(value)
239
+ fields.each_with_object({}) do |(name, limit), result|
240
+ result[name] = source[name].nil? ? nil : bounded(source[name], limit)
241
+ end
242
+ end
243
+
244
+ def hash_value(value)
245
+ value.is_a?(Hash) ? value : {}
246
+ end
247
+
248
+ def exact_keys?(value, keys)
249
+ value.is_a?(Hash) && value.keys.sort == keys.sort
250
+ end
251
+
252
+ def bounded(value, limit)
253
+ text = value.to_s.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
254
+ return text if text.bytesize <= limit
255
+
256
+ text.byteslice(0, limit).to_s.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
257
+ rescue StandardError
258
+ ""
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,108 @@
1
+ require "json"
2
+
3
+ module Chronos
4
+ module Core
5
+ # Immutable result returned by an explicit Chronos integration verification.
6
+ #
7
+ # @responsibility Expose a bounded, JSON-safe verification outcome to Ruby and Rake callers.
8
+ # @motivation Report credential, receiver, and acknowledgement state without exposing raw responses.
9
+ # @limits It never includes project keys, response bodies, stack traces, or receiver internals.
10
+ # @collaborators VerifyIntegration and Chronos::RakeTasks.
11
+ # @thread_safety The object and all nested values are immutable after construction.
12
+ # @compatibility Ruby 2.2.10 through Ruby 2.6; independent of Rails.
13
+ # @example
14
+ # result = Chronos.verify_integration
15
+ # puts result.to_json
16
+ # @errors Invalid input is normalized to safe empty values.
17
+ # @performance Construction visits only the small allowlisted verification response.
18
+ class IntegrationVerificationResult
19
+ SCHEMA_VERSION = "1.0".freeze
20
+
21
+ attr_reader :status, :verification_id, :credentials_valid, :event,
22
+ :project, :receiver, :error
23
+
24
+ def initialize(attributes = {})
25
+ @success = attributes[:success] == true
26
+ @status = safe_string(attributes[:status], 64)
27
+ @verification_id = optional_string(attributes[:verification_id], 128)
28
+ @credentials_valid = boolean_or_nil(attributes[:credentials_valid])
29
+ @event = immutable_copy(hash_value(attributes[:event]))
30
+ @project = optional_hash(attributes[:project])
31
+ @receiver = optional_hash(attributes[:receiver])
32
+ @error = optional_hash(attributes[:error])
33
+ freeze
34
+ end
35
+
36
+ def success?
37
+ @success
38
+ end
39
+
40
+ def to_h
41
+ {
42
+ "schema_version" => SCHEMA_VERSION,
43
+ "success" => success?,
44
+ "status" => status,
45
+ "verification_id" => verification_id,
46
+ "credentials_valid" => credentials_valid,
47
+ "event_received" => event["received"] == true,
48
+ "event" => event,
49
+ "project" => project,
50
+ "receiver" => receiver,
51
+ "error" => error
52
+ }
53
+ end
54
+
55
+ def to_json(*arguments)
56
+ JSON.generate(to_h, *arguments)
57
+ end
58
+
59
+ private
60
+
61
+ def optional_hash(value)
62
+ value.is_a?(Hash) ? immutable_copy(value) : nil
63
+ end
64
+
65
+ def hash_value(value)
66
+ value.is_a?(Hash) ? value : {}
67
+ end
68
+
69
+ def boolean_or_nil(value)
70
+ [true, false].include?(value) ? value : nil
71
+ end
72
+
73
+ def optional_string(value, limit)
74
+ return nil if value.nil?
75
+
76
+ safe_string(value, limit)
77
+ end
78
+
79
+ def safe_string(value, limit)
80
+ text = value.is_a?(String) || value.is_a?(Symbol) ? value.to_s : ""
81
+ text = text.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
82
+ return text if text.bytesize <= limit
83
+
84
+ text.byteslice(0, limit).to_s.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
85
+ rescue StandardError
86
+ ""
87
+ end
88
+
89
+ def immutable_copy(value)
90
+ copy = case value
91
+ when Hash
92
+ value.each_with_object({}) do |(key, child), result|
93
+ result[safe_string(key, 64)] = immutable_copy(child)
94
+ end
95
+ when Array
96
+ value.first(20).map { |child| immutable_copy(child) }
97
+ when String
98
+ safe_string(value, 512)
99
+ when NilClass, TrueClass, FalseClass, Numeric
100
+ value
101
+ else
102
+ ""
103
+ end
104
+ copy.freeze
105
+ end
106
+ end
107
+ end
108
+ end
@@ -21,4 +21,15 @@ module Chronos
21
21
  # @example
22
22
  # Chronos.configure { |config| config.project_key = nil }
23
23
  class ConfigurationError < Error; end
24
+
25
+ # Synthetic exception sent only by an explicit integration verification.
26
+ #
27
+ # @responsibility Give verification notices a stable, recognizable exception class.
28
+ # @motivation Let the Chronos receiver distinguish an integration check from an application failure.
29
+ # @limits It is never raised into the host application and carries no application data.
30
+ # @thread_safety A fresh instance is created for each verification.
31
+ # @compatibility Ruby 2.2.10 and newer legacy runtimes.
32
+ # @example
33
+ # Chronos.verify_integration
34
+ class IntegrationVerificationError < Error; end
24
35
  end
@@ -8,7 +8,7 @@ module Chronos
8
8
  # @thread_safety Immutable after construction.
9
9
  # @compatibility Ruby 2.2.10 through Ruby 2.6.
10
10
  class TransportResult
11
- attr_reader :status, :status_code, :retry_after, :error, :remote_configuration
11
+ attr_reader :status, :status_code, :retry_after, :error, :remote_configuration, :response
12
12
 
13
13
  def initialize(status, options = {})
14
14
  @status = status
@@ -16,6 +16,7 @@ module Chronos
16
16
  @retry_after = options[:retry_after]
17
17
  @error = options[:error]
18
18
  @remote_configuration = options[:remote_configuration]
19
+ @response = deep_freeze(options[:response])
19
20
  freeze
20
21
  end
21
22
 
@@ -26,6 +27,22 @@ module Chronos
26
27
  def retryable?
27
28
  [:request_timeout, :rate_limited, :server_error, :network_error].include?(status)
28
29
  end
30
+
31
+ private
32
+
33
+ def deep_freeze(value)
34
+ if value.is_a?(Hash)
35
+ value.each do |key, child|
36
+ deep_freeze(key)
37
+ deep_freeze(child)
38
+ end
39
+ elsif value.is_a?(Array)
40
+ value.each { |child| deep_freeze(child) }
41
+ end
42
+ value.freeze
43
+ rescue StandardError
44
+ nil
45
+ end
29
46
  end
30
47
 
31
48
  # Conceptual transport port implemented by delivery adapters.
@@ -16,6 +16,11 @@ module Chronos
16
16
  initializer "chronos.install", :after => :load_config_initializers do |application|
17
17
  Chronos::Rails::Installer.new.install(application)
18
18
  end
19
+
20
+ rake_tasks do
21
+ require "chronos/rake_tasks"
22
+ Chronos::RakeTasks.install(:load_environment => true)
23
+ end
19
24
  end
20
25
  end
21
26
  end
@@ -0,0 +1,41 @@
1
+ require "json"
2
+ require "rake"
3
+ require "chronos"
4
+
5
+ module Chronos
6
+ # Installs explicit Rake commands supplied by the Chronos gem.
7
+ #
8
+ # @responsibility Register the integration verification task with deterministic JSON output.
9
+ # @motivation Give Rails and plain Ruby operators one repeatable end-to-end credential check.
10
+ # @limits It never reads environment variables, prints credentials, or modifies application data.
11
+ # @collaborators Rake and Chronos.verify_integration.
12
+ # @thread_safety Installation checks the process-global Rake registry and is intended for boot time.
13
+ # @compatibility Rake versions compatible with Ruby 2.2.10 through Ruby 2.6.
14
+ # @example
15
+ # require "chronos/rake_tasks"
16
+ # Chronos::RakeTasks.install
17
+ # @errors Verification failures produce JSON and a nonzero process status.
18
+ # @performance The task performs one explicit synchronous verification when invoked.
19
+ module RakeTasks
20
+ extend ::Rake::DSL
21
+
22
+ TASK_NAME = "chronos:verify_integration".freeze
23
+
24
+ def self.install(options = {})
25
+ return false if ::Rake::Task.task_defined?(TASK_NAME)
26
+
27
+ output = options[:output] || $stdout
28
+ exiter = options[:exit] || proc { |status| exit(status) }
29
+ load_environment = options[:load_environment] || ::Rake::Task.task_defined?("environment")
30
+ prerequisites = load_environment ? ["environment"] : []
31
+
32
+ desc "Send an identified fake error and verify Chronos credentials and ingestion"
33
+ task TASK_NAME => prerequisites do
34
+ result = Chronos.verify_integration
35
+ output.puts(JSON.generate(result.to_h))
36
+ exiter.call(1) unless result.success?
37
+ end
38
+ true
39
+ end
40
+ end
41
+ end
@@ -1,4 +1,4 @@
1
1
  module Chronos
2
2
  # Current version of the legacy Chronos Ruby agent.
3
- VERSION = "0.9.0.pre.3".freeze
3
+ VERSION = "0.9.0.pre.4".freeze
4
4
  end
data/lib/chronos.rb CHANGED
@@ -7,6 +7,7 @@ require "chronos/ports"
7
7
  require "chronos/adapters"
8
8
  require "chronos/internal"
9
9
  require "chronos/core/notice"
10
+ require "chronos/core/integration_verification_result"
10
11
  require "chronos/core/backtrace_parser"
11
12
  require "chronos/core/exception_cause_collector"
12
13
  require "chronos/core/runtime_info"
@@ -36,6 +37,7 @@ require "chronos/application/remote_configuration"
36
37
  require "chronos/application/ignore_policy"
37
38
  require "chronos/application/delivery_pipeline"
38
39
  require "chronos/application/capture_exception"
40
+ require "chronos/application/verify_integration"
39
41
  require "chronos/application/apm_error_classifier"
40
42
  require "chronos/application/apm_aggregator"
41
43
  require "chronos/application/dependency_reporter"
@@ -95,6 +97,21 @@ module Chronos # rubocop:disable Metrics/ModuleLength
95
97
  false
96
98
  end
97
99
 
100
+ def verify_integration
101
+ agent = current_agent
102
+ return agent.verify_integration if agent
103
+
104
+ verification_failure(
105
+ "not_configured", "Chronos is not configured.",
106
+ "Run Chronos.configure before verifying the integration."
107
+ )
108
+ rescue StandardError
109
+ verification_failure(
110
+ "verification_failed", "Chronos integration verification failed locally.",
111
+ "Review the Chronos configuration and retry."
112
+ )
113
+ end
114
+
98
115
  def with_context(context = {})
99
116
  agent = current_agent
100
117
  return yield unless agent
@@ -186,6 +203,15 @@ module Chronos # rubocop:disable Metrics/ModuleLength
186
203
  def current_agent
187
204
  @mutex.synchronize { @agent }
188
205
  end
206
+
207
+ def verification_failure(status, message, guidance)
208
+ Core::IntegrationVerificationResult.new(
209
+ :success => false, :status => status, :credentials_valid => nil,
210
+ :event => {"id" => nil, "received" => false},
211
+ :receiver => {"name" => "chronos", "status" => "not_checked", "received_at" => nil},
212
+ :error => {"code" => status, "message" => message, "guidance" => guidance}
213
+ )
214
+ end
189
215
  end
190
216
  end
191
217
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronos-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0.pre.3
4
+ version: 0.9.0.pre.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antonio Jefferson
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: 0.49.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: parallel
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '='
80
+ - !ruby/object:Gem::Version
81
+ version: 1.19.2
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '='
87
+ - !ruby/object:Gem::Version
88
+ version: 1.19.2
75
89
  description: Base do cliente Chronos para excecoes, telemetria e observabilidade em
76
90
  aplicacoes Ruby legadas.
77
91
  email:
@@ -90,6 +104,7 @@ files:
90
104
  - contracts/dependencies-v1.schema.json
91
105
  - contracts/deploy-v1.schema.json
92
106
  - contracts/event-v1.schema.json
107
+ - contracts/integration-verification-response-v1.schema.json
93
108
  - contracts/rack-context-v1.schema.json
94
109
  - contracts/sidekiq-job-v1.schema.json
95
110
  - docs/adr/ADR-001-core-and-integrations.md
@@ -122,6 +137,7 @@ files:
122
137
  - docs/modules/deploy-tracking.md
123
138
  - docs/modules/external-http.md
124
139
  - docs/modules/ignore-rules.md
140
+ - docs/modules/integration-verification.md
125
141
  - docs/modules/notice-pipeline.md
126
142
  - docs/modules/rack-context.md
127
143
  - docs/modules/rails-legacy.md
@@ -155,6 +171,7 @@ files:
155
171
  - lib/chronos/application/ignore_policy.rb
156
172
  - lib/chronos/application/remote_configuration.rb
157
173
  - lib/chronos/application/retry_policy.rb
174
+ - lib/chronos/application/verify_integration.rb
158
175
  - lib/chronos/capistrano.rb
159
176
  - lib/chronos/configuration.rb
160
177
  - lib/chronos/configuration/apm_validation.rb
@@ -167,6 +184,7 @@ files:
167
184
  - lib/chronos/core/correlation_context.rb
168
185
  - lib/chronos/core/deploy_normalizer.rb
169
186
  - lib/chronos/core/exception_cause_collector.rb
187
+ - lib/chronos/core/integration_verification_result.rb
170
188
  - lib/chronos/core/metric_aggregate.rb
171
189
  - lib/chronos/core/notice.rb
172
190
  - lib/chronos/core/notice_builder.rb
@@ -200,6 +218,7 @@ files:
200
218
  - lib/chronos/rails/installer.rb
201
219
  - lib/chronos/rails/notifications_subscriber.rb
202
220
  - lib/chronos/rails/railtie.rb
221
+ - lib/chronos/rake_tasks.rb
203
222
  - lib/chronos/ruby.rb
204
223
  - lib/chronos/ruby/version.rb
205
224
  - lib/chronos/sidekiq.rb