Skip to content

feat(a2a-auth-callout): credentials (api_key, mtls, oidc) - #371

Merged
yordis merged 4 commits into
mainfrom
yordis/feat-a2a-auth-callout-credentials
Jun 21, 2026
Merged

feat(a2a-auth-callout): credentials (api_key, mtls, oidc)#371
yordis merged 4 commits into
mainfrom
yordis/feat-a2a-auth-callout-credentials

Conversation

@yordis

@yordis yordis commented Jun 21, 2026

Copy link
Copy Markdown
Member
  • adds the three credential verifiers the dispatcher slice will route against (HMAC API key, mTLS chain verification, OIDC discovery + JWKS), each with the typed-value-object boundary the rest of the crate already follows
  • landing them as one slice keeps each verifier paired with the test surface it ships with (rcgen-generated certs, RSA-key JWKS, wiremock-served discovery) instead of leaving partially-wired modules across PRs

Adds the three credential verifiers the dispatcher routes against:
HMAC-SHA256 API key, mTLS chain verification via x509-parser +
rustls-webpki, and OIDC discovery + JWT decode via reqwest + jwks.
Each verifier has the typed value-object pattern around its
credential material, so the dispatcher slice can wire them up
without further refactoring.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@cursor

cursor Bot commented Jun 21, 2026

Copy link
Copy Markdown

PR Summary

High Risk
New authentication paths (OIDC network trust, mTLS chain validation, API key registry) directly control who gets NATS user JWTs; mistakes or bypasses are security-critical even though API key is marked transitional.

Overview
Adds a new credentials module to a2a-auth-callout with three async verifiers that turn caller credentials into UserJwtClaims for a resolved AudienceAccount, plus a CredentialSource enum documenting preference order (OIDC → mTLS → transitional API key).

API key: HMAC-SHA256 digest registry and HmacApiKeyVerifier; verification rejects unknown keys, empty keys, and audience mismatch between the connection’s requested account and the registry entry (so a leaked key can’t target another account).

mTLS: X509MtlsVerifier validates PEM chains against configured trust anchors (validity, end-entity-only, signature walk), derives subject/caller id, and sets SpiceDB-oriented claim data.

OIDC: JwksOidcVerifier supports static or discovered JWKS (timeouts, no redirects), enforces discovery issuer match and same-origin jwks_uri, validates RS256 id tokens, then maps claims like the other paths.

Crate deps expand for HTTP/TLS/X.509 (reqwest, tokio, x509-parser, etc.); each verifier ships unit/integration tests (rcgen, RSA JWKS, wiremock). The module is exported from lib.rs but not yet wired into a dispatcher in this diff.

Reviewed by Cursor Bugbot for commit 33666d8. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yordis, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 23 minutes and 53 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 37bdd52d-5b18-4ad6-a4d3-3fe8036d8c34

📥 Commits

Reviewing files that changed from the base of the PR and between 15bb34b and 33666d8.

📒 Files selected for processing (3)
  • rsworkspace/crates/a2a-auth-callout/src/credentials/api_key.rs
  • rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs
  • rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs

Walkthrough

Adds a new credentials module to the a2a-auth-callout crate exposing three authentication verifier implementations: a deprecated HMAC-SHA256 API key verifier, an X.509 mTLS verifier using x509-parser, and a JWKS-backed OIDC/JWT verifier using reqwest and jsonwebtoken. Supporting crate dependencies are expanded in Cargo.toml.

Changes

Auth Callout Credentials Module

Layer / File(s) Summary
Crate dependencies and module wiring
rsworkspace/crates/a2a-auth-callout/Cargo.toml, src/lib.rs, src/credentials/mod.rs
Expands Cargo.toml with async-trait, reqwest (json + rustls-tls), rustls-*, x509-parser, data-encoding, additional tokio features, and dev deps (rand, rcgen, rsa, wiremock). Declares pub mod credentials in lib.rs and defines the CredentialSource enum with Oidc, MTls, and deprecated ApiKey variants in mod.rs.
API key types, registry, and deprecated verifier
src/credentials/api_key.rs
Defines ApiKeyError, ApiKey (validated newtype), ApiKeyDigest (HMAC-SHA256 over key+secret), ApiKeyRegistry (HashMap<ApiKeyDigest, ApiKeyEntry>), deprecated ApiKeyVerifier trait, and HmacApiKeyVerifier. Tests cover empty-key rejection, unknown-key failure, successful claim generation, digest determinism, and registry overwrite.
mTLS X.509 verifier
src/credentials/mtls.rs
Adds ClientCertPem/TrustAnchorPem wrappers, X509MtlsVerifier with synchronous PEM parsing, trust-anchor loading, leaf validity checking, issuer-to-anchor signature verification, ExternalSubject extraction (DN or DER fallback), and UserJwtClaims population. The async MTlsVerifier trait delegates to verify_sync with current UTC time. Tests cover empty anchor bundle, valid CA/leaf chain, and issuer-mismatch rejection.
OIDC/JWT JWKS-backed verifier
src/credentials/oidc.rs
Defines OidcIssuerUrl, OidcClientId, BearerToken wrappers; JwksSource enum for remote (reqwest) vs. static JWKS; JwksOidcVerifier with OIDC discovery, JWKS fetching, RSA-only JWK decoding, kid-based key selection, issuer/audience JWT validation, and UserJwtClaims construction. The async OidcVerifier trait delegates to verify_internal. Tests cover empty-audience, RS256 happy path, bad signature, and WireMock-backed discovery.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(70, 130, 180, 0.5)
        Note over Client,UserJwtClaims: OIDC Path
        Client->>JwksOidcVerifier: verify(BearerToken, AudienceAccount)
        JwksOidcVerifier->>JwksSource: fetch_jwks()
        JwksSource->>reqwest: GET jwks_uri (if Remote)
        reqwest-->>JwksSource: JwkSet
        JwksOidcVerifier->>jsonwebtoken: decode header → kid
        JwksOidcVerifier->>jsonwebtoken: validate JWT (issuer + audiences)
        JwksOidcVerifier->>JwksOidcVerifier: sub → ExternalSubject → caller_id
        JwksOidcVerifier-->>Client: Ok(UserJwtClaims)
    end
    rect rgba(60, 179, 113, 0.5)
        Note over Client,UserJwtClaims: mTLS Path
        Client->>X509MtlsVerifier: verify(ClientCertPem, AudienceAccount)
        X509MtlsVerifier->>x509_parser: parse leaf PEM + trust anchors
        X509MtlsVerifier->>X509MtlsVerifier: check validity at now_utc
        X509MtlsVerifier->>X509MtlsVerifier: match issuer to anchor, verify signature
        X509MtlsVerifier->>X509MtlsVerifier: extract ExternalSubject (DN or DER fallback)
        X509MtlsVerifier-->>Client: Ok(UserJwtClaims)
    end
    rect rgba(210, 105, 30, 0.5)
        Note over Client,UserJwtClaims: API Key Path (deprecated)
        Client->>HmacApiKeyVerifier: verify(api_key: &str)
        HmacApiKeyVerifier->>ApiKeyDigest: HMAC-SHA256(key, secret)
        HmacApiKeyVerifier->>ApiKeyRegistry: lookup(digest)
        ApiKeyRegistry-->>HmacApiKeyVerifier: ApiKeyEntry
        HmacApiKeyVerifier-->>Client: Ok(UserJwtClaims)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

rust:coverage-baseline-reset

Poem

🐇 Hopping through the certs and keys,
Three new verifiers in the trees!
OIDC JWTs, mTLS chains,
API keys (deprecated) with HMAC pains.
Each digest, each anchor, each kid in line —
This rabbit says the auth flows look fine! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding three credential verifiers (API key, mTLS, OIDC) to the a2a-auth-callout crate.
Description check ✅ Passed The description clearly explains the purpose and scope of the changes, detailing the three credential verifiers and the reasoning for consolidating them.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/feat-a2a-auth-callout-credentials

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

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

Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/api_key.rs
@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown

badge

Code Coverage Summary

Details
Filename                                                                                  Stmts    Miss  Cover    Missing
--------------------------------------------------------------------------------------  -------  ------  -------  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
crates/a2a-nats/src/catalog/store.rs                                                        382       0  100.00%
crates/a2a-nats/src/catalog/nats_kv.rs                                                       19       0  100.00%
crates/a2a-nats/src/catalog/registrar.rs                                                    211       0  100.00%
crates/a2a-nats/src/catalog/watch.rs                                                         99       0  100.00%
crates/mcp-nats/src/config.rs                                                               110       0  100.00%
crates/mcp-nats/src/jsonrpc.rs                                                               22       0  100.00%
crates/mcp-nats/src/server.rs                                                                31       0  100.00%
crates/mcp-nats/src/transport.rs                                                            698       0  100.00%
crates/mcp-nats/src/client.rs                                                                31       0  100.00%
crates/mcp-nats/src/mcp_peer_id.rs                                                           31       0  100.00%
crates/mcp-nats/src/mcp_prefix.rs                                                            34       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_payload_decode.rs                   3       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_encode_error.rs                    36       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/encoded_snapshot.rs                        117       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_decode_error.rs                    49       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_decode_error.rs           28       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_encode_error.rs           14       0  100.00%
crates/acp-nats/src/error.rs                                                                 82       0  100.00%
crates/acp-nats/src/req_id.rs                                                                39       0  100.00%
crates/acp-nats/src/jsonrpc.rs                                                                6       0  100.00%
crates/acp-nats/src/ext_method_name.rs                                                       65       0  100.00%
crates/acp-nats/src/acp_prefix.rs                                                            46       0  100.00%
crates/acp-nats/src/session_id.rs                                                            68       0  100.00%
crates/acp-nats/src/config.rs                                                               203       0  100.00%
crates/acp-nats/src/client_proxy.rs                                                         181       0  100.00%
crates/acp-nats/src/lib.rs                                                                   69       0  100.00%
crates/acp-nats/src/in_flight_slot_guard.rs                                                  32       0  100.00%
crates/acp-nats/src/pending_prompt_waiters.rs                                               131       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/all_server.rs                                 6       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/one_client.rs                                 9       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/one_server.rs                                 9       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/all_client.rs                                 6       0  100.00%
crates/mcp-nats-stdio/src/main.rs                                                           204       0  100.00%
crates/mcp-nats-stdio/src/config.rs                                                         149       0  100.00%
crates/trogon-gateway/src/source/notion/notion_verification_token.rs                         17       0  100.00%
crates/trogon-gateway/src/source/notion/notion_event_type.rs                                 46       3  93.48%   50-52
crates/trogon-gateway/src/source/notion/signature.rs                                         45       0  100.00%
crates/trogon-gateway/src/source/notion/verification_token.rs                               220       0  100.00%
crates/trogon-gateway/src/source/notion/server.rs                                           310       4  98.71%   115-116, 135-136
crates/mcp-nats/src/telemetry/transport.rs                                                    6       0  100.00%
crates/trogon-nats/src/token.rs                                                               6       0  100.00%
crates/trogon-nats/src/mocks.rs                                                             314       0  100.00%
crates/trogon-nats/src/auth.rs                                                              114       0  100.00%
crates/trogon-nats/src/client.rs                                                             22      22  0.00%    50-86
crates/trogon-nats/src/connect.rs                                                            82       6  92.68%   41-46
crates/trogon-nats/src/nats_token.rs                                                        157       0  100.00%
crates/trogon-nats/src/server_info.rs                                                        76       3  96.05%   19-21
crates/trogon-nats/src/subject_token_violation.rs                                            11       0  100.00%
crates/trogon-nats/src/messaging.rs                                                         534       2  99.63%   144, 154
crates/trogon-gateway/src/source/twitter/config.rs                                           17       0  100.00%
crates/trogon-gateway/src/source/twitter/signature.rs                                        58       0  100.00%
crates/trogon-gateway/src/source/twitter/server.rs                                          524       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/failure.rs                       38       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/codec.rs                        641      68  89.39%   134, 140, 149, 192, 208-210, 227, 244-246, 415, 417-419, 453-464, 480-481, 486-487, 493-494, 507-508, 513-514, 519-523, 529-530, 545-546, 551-552, 558-559, 566-567, 572-573, 585-589, 595-597, 612-618, 626, 631-633, 643, 648
crates/trogon-scheduler/src/processor/execution/checkpoints/record.rs                         6       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/store.rs                        407      17  95.82%   102, 120, 124, 132, 224-230, 236, 279-283
crates/a2a-nats/src/nats/subjects/agents/card.rs                                             20       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/message_send.rs                                     23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/message_stream.rs                                   23       0  100.00%
crates/trogon-nats/src/telemetry/messaging.rs                                                82       0  100.00%
crates/trogon-scheduler/src/processor/execution/execution_schedules/mod.rs                  270       0  100.00%
crates/a2a-auth-callout/src/jwt/nats_user_jwt.rs                                            232      21  90.95%   131, 178, 187-196, 209, 214, 228, 237-242, 284, 288, 313
crates/a2a-auth-callout/src/jwt/user_jwt_subject.rs                                          12       6  50.00%   18-26
crates/a2a-auth-callout/src/jwt/nats_permission_claims.rs                                    10       0  100.00%
crates/a2a-auth-callout/src/jwt/mod.rs                                                      328     116  64.63%   28-31, 45-51, 59-78, 115-118, 123, 181, 185-187, 196-220, 243, 252-254, 273, 280-283, 306-308, 311-313, 319-330, 362-392, 413-420, 444, 449-453
crates/a2a-nats/src/audit/envelope.rs                                                       204       0  100.00%
crates/a2a-nats/src/audit/emitter.rs                                                        160       0  100.00%
crates/a2a-nats/src/audit/task_lifecycle.rs                                                  17       0  100.00%
crates/acp-nats/src/nats/subjects/mod.rs                                                    362       0  100.00%
crates/acp-nats/src/nats/subjects/stream.rs                                                  56       0  100.00%
crates/a2a-nats/src/nats/subjects/stream.rs                                                  54       0  100.00%
crates/a2a-identity-types/src/caller.rs                                                      61       0  100.00%
crates/a2a-identity-types/src/jwt.rs                                                        156       0  100.00%
crates/a2a-identity-types/src/error.rs                                                       20       0  100.00%
crates/a2a-identity-types/src/principal.rs                                                   40       0  100.00%
crates/a2a-pack/src/agent_card_read.rs                                                       66       0  100.00%
crates/a2a-pack/src/agent_card_schema.rs                                                     81       0  100.00%
crates/trogon-gateway/src/source/standard_webhooks.rs                                       138       0  100.00%
crates/trogon-gateway/src/source/sentry/sentry_client_secret.rs                              17       0  100.00%
crates/trogon-gateway/src/source/sentry/signature.rs                                         42       0  100.00%
crates/trogon-gateway/src/source/sentry/server.rs                                           308       0  100.00%
crates/trogon-std/src/fs/mem.rs                                                             216      10  95.37%   61-63, 77-79, 132-134, 157
crates/trogon-std/src/fs/system.rs                                                           92       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_mode.rs                                       15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/close.rs                                          15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/resume.rs                                         15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/prompt.rs                                         15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/cancel.rs                                         15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_config_option.rs                              15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/fork.rs                                           15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_model.rs                                      15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/load.rs                                           15       0  100.00%
crates/trogon-decider-runtime/src/snapshot/mod.rs                                             3       0  100.00%
crates/trogon-decider-runtime/src/snapshot/read_snapshot.rs                                  11       0  100.00%
crates/trogon-decider-runtime/src/snapshot/snapshot_type.rs                                  73       0  100.00%
crates/trogon-scheduler/src/commands/pause_schedule.rs                                      174       0  100.00%
crates/trogon-scheduler/src/commands/state.rs                                               472       0  100.00%
crates/trogon-scheduler/src/commands/record_schedule_occurrence.rs                          348       1  99.71%   182
crates/trogon-scheduler/src/commands/schedule_next_occurrence.rs                            355       0  100.00%
crates/trogon-scheduler/src/commands/snapshot.rs                                              4       0  100.00%
crates/trogon-scheduler/src/commands/resume_schedule.rs                                     207       0  100.00%
crates/trogon-scheduler/src/commands/remove_schedule.rs                                     171       0  100.00%
crates/trogon-scheduler/src/commands/create_schedule.rs                                     199       0  100.00%
crates/mcp-nats/src/nats/subjects/client/progress.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/cancelled.rs                                        12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/initialized.rs                                      12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/roots_list_changed.rs                               12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/create_elicitation.rs                               12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/list_roots.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/ping.rs                                              9       0  100.00%
crates/mcp-nats/src/nats/subjects/client/create_message.rs                                   12       0  100.00%
crates/trogon-gateway/src/source/discord/gateway.rs                                         426       1  99.77%   137
crates/trogon-gateway/src/source/discord/config.rs                                          105       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/set.rs                                         20       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/delete.rs                                      23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/get.rs                                         20       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/list.rs                                        23       0  100.00%
crates/trogon-gateway/src/source/github/config.rs                                            17       0  100.00%
crates/trogon-gateway/src/source/github/server.rs                                           328       0  100.00%
crates/trogon-gateway/src/source/github/signature.rs                                         50       0  100.00%
crates/trogon-decider-runtime/src/execution.rs                                             1432       0  100.00%
crates/a2a-auth-callout/src/credentials/mtls.rs                                             196      19  90.31%   61-63, 78, 115-117, 126-130, 146, 148-149, 163-164, 202-204
crates/a2a-auth-callout/src/credentials/oidc.rs                                             397      22  94.46%   18-19, 21-23, 48-50, 158, 162, 176, 211-213, 250-251, 274-276, 302, 443, 499, 518
crates/a2a-auth-callout/src/credentials/api_key.rs                                          121       6  95.04%   31, 41-46
crates/acp-nats-agent/src/connection.rs                                                    1252       1  99.92%   583
crates/trogon-decider-nats/src/snapshot_store.rs                                            861      27  96.86%   208-210, 248-250, 361-367, 449, 585, 590, 686-688, 694-696, 730-731, 741-742, 761, 789-790
crates/trogon-decider-nats/src/store.rs                                                     128      45  64.84%   50-54, 101-167
crates/trogon-decider-nats/src/stream_store.rs                                              659      18  97.27%   70-72, 245, 273-274, 277, 293-297, 464-465, 506, 519-523
crates/trogon-nats/src/lease/lease_bucket.rs                                                 19       0  100.00%
crates/trogon-nats/src/lease/ttl.rs                                                          68       0  100.00%
crates/trogon-nats/src/lease/nats_kv_lease_config.rs                                         26       0  100.00%
crates/trogon-nats/src/lease/lease_key.rs                                                    19       0  100.00%
crates/trogon-nats/src/lease/renew.rs                                                       246      19  92.28%   23-29, 48-59
crates/trogon-nats/src/lease/acquire.rs                                                       5       5  0.00%    9-14
crates/trogon-nats/src/lease/mod.rs                                                         523      13  97.51%   113-126
crates/trogon-nats/src/lease/provision.rs                                                   187      10  94.65%   82-92
crates/trogon-nats/src/lease/release.rs                                                       5       5  0.00%    8-12
crates/trogon-nats/src/lease/renew_interval.rs                                               57       0  100.00%
crates/trogon-nats/src/lease/lease_timing.rs                                                 15       0  100.00%
crates/trogon-std/src/telemetry/http.rs                                                     217       0  100.00%
crates/trogonai-proto/src/codec.rs                                                           16       0  100.00%
crates/trogonai-proto/src/convert.rs                                                        120       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs                       83       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_id.rs                                   81       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs                20       0  100.00%
crates/trogon-scheduler/src/commands/domain/recurrence.rs                                   179       1  99.44%   99
crates/trogon-scheduler/src/commands/domain/schedule.rs                                     638       0  100.00%
crates/trogon-scheduler/src/commands/domain/message.rs                                      219       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs                       25       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs                         10       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_occurrence_sequence.rs                  30       0  100.00%
crates/trogon-gateway/src/source/telegram/config.rs                                          89       0  100.00%
crates/trogon-gateway/src/source/telegram/server.rs                                         339       0  100.00%
crates/trogon-gateway/src/source/telegram/registration.rs                                   313       0  100.00%
crates/trogon-gateway/src/source/telegram/signature.rs                                       27       0  100.00%
crates/a2a-nats/src/jetstream/streams.rs                                                     73       0  100.00%
crates/a2a-nats/src/jetstream/stream_options.rs                                             114       0  100.00%
crates/a2a-nats/src/jetstream/consumers.rs                                                  112       0  100.00%
crates/a2a-nats/src/jetstream/provision.rs                                                   62       0  100.00%
crates/mcp-nats/src/nats/parsing.rs                                                         191       0  100.00%
crates/mcp-nats/src/nats/mod.rs                                                              99       0  100.00%
crates/acp-nats/src/client/terminal_output.rs                                               206       0  100.00%
crates/acp-nats/src/client/ext.rs                                                           296       8  97.30%   146-155, 172-181
crates/acp-nats/src/client/terminal_kill.rs                                                 278       0  100.00%
crates/acp-nats/src/client/terminal_release.rs                                              335       0  100.00%
crates/acp-nats/src/client/request_permission.rs                                            298       0  100.00%
crates/acp-nats/src/client/terminal_wait_for_exit.rs                                        364       0  100.00%
crates/acp-nats/src/client/rpc_reply.rs                                                      64       0  100.00%
crates/acp-nats/src/client/mod.rs                                                          2851       0  100.00%
crates/acp-nats/src/client/session_update.rs                                                 55       0  100.00%
crates/acp-nats/src/client/fs_read_text_file.rs                                             346       0  100.00%
crates/acp-nats/src/client/terminal_create.rs                                               264       0  100.00%
crates/acp-nats/src/client/ext_session_prompt_response.rs                                   135       0  100.00%
crates/acp-nats/src/client/fs_write_text_file.rs                                            408       0  100.00%
crates/acp-nats/src/nats/subjects/global/initialize.rs                                        6       0  100.00%
crates/acp-nats/src/nats/subjects/global/session_list.rs                                      6       0  100.00%
crates/acp-nats/src/nats/subjects/global/session_new.rs                                       6       0  100.00%
crates/acp-nats/src/nats/subjects/global/authenticate.rs                                      6       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext_notify.rs                                        9       0  100.00%
crates/acp-nats/src/nats/subjects/global/logout.rs                                            6       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext.rs                                               9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_client.rs                                 9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_agent.rs                                  9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_agent.rs                                 15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_client.rs                                15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_session.rs                                9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/global_all.rs                                 9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_session.rs                               12       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_agent_ext.rs                              9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/prompt_wildcard.rs                            9       0  100.00%
crates/a2a-nats/src/push/dispatcher/nats.rs                                                 183       0  100.00%
crates/a2a-nats/src/push/dispatcher/jetstream.rs                                            226       0  100.00%
crates/a2a-nats/src/push/dispatcher/composite.rs                                            154       0  100.00%
crates/a2a-nats/src/push/dispatcher/http.rs                                                 141       0  100.00%
crates/a2a-nats/src/push/dispatcher/mod.rs                                                   88       0  100.00%
crates/trogon-decider-runtime/src/headers/header_map.rs                                      54       3  94.44%   20-22
crates/trogon-decider-runtime/src/headers/header_name.rs                                     28       0  100.00%
crates/trogon-decider-runtime/src/headers/header_value.rs                                    34       0  100.00%
crates/trogon-decider-runtime/src/headers/mod.rs                                             74       0  100.00%
crates/a2a-nats-http/src/handlers/mod.rs                                                    185      68  63.24%   52-57, 64, 68, 74, 88-91, 95, 111, 115, 121, 125, 143-176, 182, 185, 190-196, 200-206, 210-216, 220-221
crates/a2a-nats-stdio/src/io_loop.rs                                                         84       0  100.00%
crates/a2a-nats-stdio/src/main.rs                                                             4       0  100.00%
crates/a2a-nats-stdio/src/wire.rs                                                            57       0  100.00%
crates/a2a-nats-stdio/src/runtime.rs                                                        102       0  100.00%
crates/a2a-nats-stdio/src/dispatch.rs                                                       839      11  98.69%   116, 119-121, 229, 232-234, 668, 1058, 1068
crates/trogon-decider-runtime/src/event/event_identity.rs                                     3       0  100.00%
crates/trogon-decider-runtime/src/event/mod.rs                                              170       0  100.00%
crates/trogon-decider-runtime/src/event/stream_event.rs                                       8       0  100.00%
crates/trogon-decider-runtime/src/event/event_id.rs                                          32       0  100.00%
crates/trogon-gateway/src/source/gitlab/server.rs                                           460       0  100.00%
crates/trogon-gateway/src/source/gitlab/signature.rs                                        165       0  100.00%
crates/trogon-gateway/src/source/gitlab/gitlab_signing_token.rs                              62       0  100.00%
crates/trogon-telemetry/src/resource_attribute.rs                                            23       0  100.00%
crates/trogon-telemetry/src/trace.rs                                                         23       1  95.65%   24
crates/trogon-telemetry/src/lib.rs                                                          208      24  88.46%   56, 120, 125, 130, 140-141, 147-165, 201, 204, 207, 213
crates/trogon-telemetry/src/metric.rs                                                        26       1  96.15%   30
crates/trogon-telemetry/src/service_name.rs                                                  44       0  100.00%
crates/trogon-telemetry/src/log.rs                                                           70       1  98.57%   35
crates/trogon-std/src/secret_string.rs                                                       32       0  100.00%
crates/trogon-std/src/args.rs                                                                19       9  52.63%   11-28
crates/trogon-std/src/duration.rs                                                            42       0  100.00%
crates/trogon-std/src/json.rs                                                                30       0  100.00%
crates/trogon-std/src/uuid.rs                                                                 7       0  100.00%
crates/trogon-std/src/http.rs                                                                19       0  100.00%
crates/trogon-std/src/signal.rs                                                              26      12  53.85%   6-11, 18-25, 34
crates/trogon-gateway/src/source/slack/config.rs                                             58       0  100.00%
crates/trogon-gateway/src/source/slack/signature.rs                                          66       0  100.00%
crates/trogon-gateway/src/source/slack/server.rs                                            853       0  100.00%
crates/trogon-gateway/src/source/slack/socket_mode.rs                                       716       0  100.00%
crates/trogon-gateway/src/http.rs                                                           145       0  100.00%
crates/trogon-gateway/src/source_plugin.rs                                                  268       3  98.88%   82, 139-140
crates/trogon-gateway/src/source_status.rs                                                   24       0  100.00%
crates/trogon-gateway/src/config.rs                                                        2588      42  98.38%   81, 665, 668, 828, 885, 968, 971, 974, 978, 1062-1069, 1146, 1149, 1152, 1157, 1215, 1218, 1221, 1300, 1303, 1306, 1310, 1374, 1377, 1380, 1443, 1446, 1449, 1454, 1529, 1532, 1535, 1540, 1598, 1601, 1604, 1817-1819
crates/trogon-gateway/src/main.rs                                                           111       0  100.00%
crates/trogon-gateway/src/source_integration_id.rs                                           55       2  96.36%   58, 60
crates/trogon-gateway/src/streams.rs                                                        129       0  100.00%
crates/a2a-nats/src/nats/subjects/tasks/events.rs                                            31       0  100.00%
crates/a2a-nats/src/gateway_ingress.rs                                                      243       0  100.00%
crates/a2a-nats/src/config.rs                                                               318       0  100.00%
crates/a2a-nats/src/a2a_prefix.rs                                                            44       0  100.00%
crates/a2a-nats/src/agent_id.rs                                                              58       0  100.00%
crates/a2a-nats/src/constants.rs                                                             36       0  100.00%
crates/a2a-nats/src/error.rs                                                                 32       0  100.00%
crates/a2a-nats/src/context_id.rs                                                            51       1  98.04%   26
crates/a2a-nats/src/task_id.rs                                                               54       1  98.15%   25
crates/a2a-nats/src/req_id.rs                                                                41       0  100.00%
crates/a2a-nats/src/jsonrpc.rs                                                               49       0  100.00%
crates/trogon-scheduler/src/processor/execution/wakeup.rs                                   353       7  98.02%   83-85, 127, 400, 416, 585
crates/a2a-auth-callout/src/signing_key_source/vault.rs                                       3       0  100.00%
crates/a2a-auth-callout/src/signing_key_source/file.rs                                       38       6  84.21%   40-42, 61-63
crates/a2a-auth-callout/src/signing_key_source/minting_material.rs                           18       6  66.67%   31-36
crates/a2a-auth-callout/src/signing_key_source/loader.rs                                     18      18  0.00%    7-35
crates/a2a-auth-callout/src/signing_key_source/signing_key_handle.rs                         15       6  60.00%   15-20
crates/a2a-auth-callout/src/signing_key_source/env.rs                                        38       4  89.47%   58, 75-77
crates/a2a-auth-callout/src/signing_key_source/key_version.rs                                20       8  60.00%   15-19, 28, 39-41
crates/a2a-auth-callout/src/signing_key_source/static_source.rs                              25       4  84.00%   15-20
crates/a2a-nats/src/push/target.rs                                                           54       0  100.00%
crates/a2a-nats/src/push/dispatch_error.rs                                                  111       0  100.00%
crates/a2a-nats/src/push/terminal_push_task_state.rs                                         64       0  100.00%
crates/a2a-nats/src/push/idempotency_key_header.rs                                           43       0  100.00%
crates/a2a-nats/src/push/dlq.rs                                                             283       0  100.00%
crates/a2a-nats/src/push/dlq_dedup.rs                                                       120       0  100.00%
crates/a2a-nats/src/push/push_idempotency_key.rs                                             84       0  100.00%
crates/a2a-nats/src/push/caller_id.rs                                                        91       0  100.00%
crates/a2a-nats/src/push/push_payload.rs                                                     88       0  100.00%
crates/a2a-nats/src/push/authentication_header.rs                                           104       0  100.00%
crates/a2a-nats/src/push/push_delivery_semantics_registry.rs                                 57       0  100.00%
crates/a2a-nats/src/push/status_transition_id.rs                                             30       0  100.00%
crates/a2a-nats/src/push/push_notification_config.rs                                         20       0  100.00%
crates/a2a-nats/src/push/nats_push_subject.rs                                                34       0  100.00%
crates/a2a-nats/src/push/delivery_semantics.rs                                              274       0  100.00%
crates/a2a-nats/src/push/push_notification_target.rs                                        108       0  100.00%
crates/a2a-nats/src/push/push_notification_config_id.rs                                      41       0  100.00%
crates/acp-nats-stdio/src/main.rs                                                           135      25  81.48%   67, 115-122, 128-130, 147, 176-195
crates/acp-nats-stdio/src/config.rs                                                          66       0  100.00%
crates/trogon-decider/src/testing.rs                                                        675       0  100.00%
crates/trogon-decider/src/decision.rs                                                        27       0  100.00%
crates/trogon-decider/src/events.rs                                                          49       0  100.00%
crates/trogon-decider/src/act.rs                                                             62       0  100.00%
crates/trogon-decider/src/lib.rs                                                            138       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/request.rs                   542       2  99.63%   285, 290
crates/trogon-scheduler/src/processor/execution/reconciliation/schedule_key.rs               67       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/go_duration.rs                59       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/recorded_events.rs           690      16  97.68%   200-205, 242, 250, 271, 291, 297, 303, 336, 346, 364, 448, 533, 541, 818, 1034
crates/trogon-scheduler/src/processor/execution/reconciliation/reconcile.rs                 808      13  98.39%   251-260, 325-327
crates/trogon-scheduler/src/processor/execution/reconciliation/rrule_wakeup_payload.rs       35       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/schedule_subject.rs           59       3  94.92%   60-62
crates/trogon-scheduler/src/processor/execution/worker/dispatcher.rs                       1095       1  99.91%   200
crates/trogon-scheduler/src/processor/execution/worker/testkit.rs                           330       4  98.79%   459, 490-491, 496
crates/trogon-scheduler/src/processor/execution/worker/consumer.rs                          203       0  100.00%
crates/trogon-scheduler/src/processor/execution/worker/processor.rs                        1356      12  99.12%   279, 339, 437-438, 444, 499-501, 533-536
crates/a2a-nats/src/server/agent_card.rs                                                    191       0  100.00%
crates/a2a-nats/src/server/message_stream.rs                                                265       0  100.00%
crates/a2a-nats/src/server/tasks_cancel.rs                                                  103       0  100.00%
crates/a2a-nats/src/server/push_list.rs                                                     104       0  100.00%
crates/a2a-nats/src/server/push_delete.rs                                                    97       0  100.00%
crates/a2a-nats/src/server/dispatch.rs                                                      113       0  100.00%
crates/a2a-nats/src/server/message_send.rs                                                  114       0  100.00%
crates/a2a-nats/src/server/tasks_resubscribe.rs                                             103       0  100.00%
crates/a2a-nats/src/server/handler.rs                                                        70       0  100.00%
crates/a2a-nats/src/server/test_support.rs                                                   41       0  100.00%
crates/a2a-nats/src/server/push_set.rs                                                       99       0  100.00%
crates/a2a-nats/src/server/tasks_list.rs                                                     97       0  100.00%
crates/a2a-nats/src/server/bridge.rs                                                        282       0  100.00%
crates/a2a-nats/src/server/tasks_get.rs                                                     103       0  100.00%
crates/a2a-nats/src/server/push_get.rs                                                      106       0  100.00%
crates/a2a-nats/src/server/wire.rs                                                          120       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_signing_secret.rs                     56       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_event_type.rs                         62       0  100.00%
crates/trogon-gateway/src/source/incidentio/config.rs                                        16       0  100.00%
crates/trogon-gateway/src/source/incidentio/server.rs                                       343       0  100.00%
crates/trogon-gateway/src/source/incidentio/signature.rs                                    206       0  100.00%
crates/trogon-gateway/src/source/linear/config.rs                                            17       0  100.00%
crates/trogon-gateway/src/source/linear/server.rs                                           386       0  100.00%
crates/trogon-gateway/src/source/linear/signature.rs                                         54       1  98.15%   16
crates/trogon-service-config/src/lib.rs                                                      92       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/cancel.rs                                     23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/get.rs                                        23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/list.rs                                       23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/resubscribe.rs                                23       0  100.00%
crates/mcp-nats-server/src/main.rs                                                          357     127  64.43%   151-168, 204-206, 216, 222-223, 230-233, 257-259, 263-272, 294-307, 312-360, 491, 494, 502-544
crates/mcp-nats-server/src/allowed_host.rs                                                   88       0  100.00%
crates/mcp-nats-server/src/config.rs                                                        257       0  100.00%
crates/a2a-nats/src/catalog/import_gate/error.rs                                              9       0  100.00%
crates/a2a-nats/src/catalog/import_gate/principal.rs                                         14       0  100.00%
crates/a2a-nats/src/catalog/import_gate/allow_all.rs                                          2       0  100.00%
crates/acp-nats/src/agent/bridge.rs                                                         123       4  96.75%   108-111
crates/acp-nats/src/agent/ext_notification.rs                                                82       0  100.00%
crates/acp-nats/src/agent/new_session.rs                                                     82       0  100.00%
crates/acp-nats/src/agent/set_session_mode.rs                                                67       0  100.00%
crates/acp-nats/src/agent/close_session.rs                                                   63       0  100.00%
crates/acp-nats/src/agent/initialize.rs                                                      79       0  100.00%
crates/acp-nats/src/agent/cancel.rs                                                         101       0  100.00%
crates/acp-nats/src/agent/list_sessions.rs                                                   47       0  100.00%
crates/acp-nats/src/agent/set_session_config_option.rs                                       67       0  100.00%
crates/acp-nats/src/agent/ext_method.rs                                                      82       0  100.00%
crates/acp-nats/src/agent/authenticate.rs                                                    49       0  100.00%
crates/acp-nats/src/agent/load_session.rs                                                    89       0  100.00%
crates/acp-nats/src/agent/logout.rs                                                          49       0  100.00%
crates/acp-nats/src/agent/mod.rs                                                             65       0  100.00%
crates/acp-nats/src/agent/resume_session.rs                                                  90       0  100.00%
crates/acp-nats/src/agent/set_session_model.rs                                               67       0  100.00%
crates/acp-nats/src/agent/fork_session.rs                                                    94       0  100.00%
crates/acp-nats/src/agent/test_support.rs                                                   267       0  100.00%
crates/acp-nats/src/agent/prompt.rs                                                         471       0  100.00%
crates/acp-nats/src/agent/js_request.rs                                                     283       0  100.00%
crates/a2a-auth-callout/src/denial_claims.rs                                                135      30  77.78%   21-25, 34, 53-57, 66, 85-89, 98, 125-150
crates/a2a-auth-callout/src/test_support.rs                                                  20      20  0.00%    16-36
crates/a2a-auth-callout/src/permissions.rs                                                  179      19  89.39%   16-34, 126-139
crates/a2a-auth-callout/src/denial_reason.rs                                                 35       0  100.00%
crates/a2a-auth-callout/src/account_resolver.rs                                              56       4  92.86%   34, 79-81
crates/a2a-auth-callout/src/error.rs                                                        104       0  100.00%
crates/a2a-auth-callout/src/caller_jwt_header.rs                                             20      20  0.00%    11-39
crates/a2a-auth-callout/src/denial_category.rs                                              101       1  99.01%   40
crates/a2a-auth-callout/src/main.rs                                                           4       0  100.00%
crates/a2a-auth-callout/src/wire/xkey_public.rs                                              51       0  100.00%
crates/a2a-auth-callout/src/wire/nkey_seed.rs                                                61       0  100.00%
crates/a2a-auth-callout/src/wire/nkey_public.rs                                              42       0  100.00%
crates/a2a-nats-server/src/noop_handler.rs                                                  183       0  100.00%
crates/a2a-nats-server/src/runtime.rs                                                        98       0  100.00%
crates/a2a-nats-server/src/main.rs                                                            4       0  100.00%
crates/a2a-nats/src/client/handle.rs                                                        934       0  100.00%
crates/a2a-nats/src/client/resubscribe.rs                                                    69       0  100.00%
crates/a2a-nats/src/client/wire.rs                                                           38       0  100.00%
crates/a2a-nats/src/client/streaming.rs                                                     236       0  100.00%
crates/a2a-nats/src/client/gateway_headers.rs                                                68       0  100.00%
crates/a2a-nats/src/client/unary.rs                                                         187       0  100.00%
crates/a2a-nats/src/client/error.rs                                                         161       2  98.76%   135, 144
crates/a2a-nats/src/client/event_stream.rs                                                  247       0  100.00%
crates/acp-nats-server/src/config.rs                                                        126       3  97.62%   41-43
crates/acp-nats-server/src/acp_connection_id.rs                                              37       0  100.00%
crates/acp-nats-server/src/connection.rs                                                    182      36  80.22%   95-102, 107-122, 138, 140-141, 146, 155-156, 161, 165, 169, 172, 180, 184, 187, 190-194, 232
crates/acp-nats-server/src/transport.rs                                                    1915     106  94.46%   253, 512, 530, 557, 611, 616, 636, 648, 767, 790-792, 844, 861-864, 960-963, 1038, 1041, 1044, 1053, 1057, 1060, 1063-1066, 1085, 1118-1121, 1129-1134, 1146-1150, 1154-1163, 1175-1176, 1194-1195, 1205, 1221-1225, 1253-1259, 1279-1281, 1286-1290, 1293-1298, 1315, 1317-1318, 1400-1401, 1413-1414, 1434-1435, 1487-1503, 2208, 2252, 2305, 2361, 2374
crates/acp-nats-server/src/main.rs                                                          900      10  98.89%   109, 243-250, 450
crates/a2a-nats/src/nats/subjects/subscriptions/task_one_events.rs                           20       0  100.00%
crates/a2a-nats/src/nats/subjects/subscriptions/agent_all.rs                                 20       0  100.00%
crates/a2a-nats/src/nats/subjects/subscriptions/task_all_events.rs                           17       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_release.rs                             12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/fs_write_text_file.rs                           12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/session_request_permission.rs                   12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/fs_read_text_file.rs                            12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_create.rs                              12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_wait_for_exit.rs                       12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/session_update.rs                               12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_kill.rs                                12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_output.rs                              12       0  100.00%
crates/acp-nats/src/nats/subjects/responses/cancelled.rs                                     15       0  100.00%
crates/acp-nats/src/nats/subjects/responses/ext_ready.rs                                     12       0  100.00%
crates/acp-nats/src/nats/subjects/responses/response.rs                                      20       0  100.00%
crates/acp-nats/src/nats/subjects/responses/prompt_response.rs                               27       0  100.00%
crates/acp-nats/src/nats/subjects/responses/update.rs                                        27       0  100.00%
crates/acp-nats/src/telemetry/metrics.rs                                                     53       0  100.00%
crates/mcp-nats/src/nats/subjects/mod.rs                                                     89       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_prompts.rs                                     12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_tools.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/progress.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/resource_list_changed.rs                            12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/set_logging_level.rs                                12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/tool_list_changed.rs                                12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/subscribe_resource.rs                               12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/get_prompt.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/resource_updated.rs                                 12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/get_task.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_tasks.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/prompt_list_changed.rs                              12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/initialize.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/cancel_task.rs                                      12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/cancelled.rs                                        12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_resource_templates.rs                          12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/logging_message.rs                                  12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/elicitation_completed.rs                            12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/get_task_result.rs                                  12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/complete.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/call_tool.rs                                        12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/unsubscribe_resource.rs                             12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_resources.rs                                   12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/read_resource.rs                                    12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/ping.rs                                              9       0  100.00%
crates/a2a-nats-http/src/router.rs                                                           55      14  74.55%   59-63, 69-79
crates/a2a-nats-http/src/headers.rs                                                         167       6  96.41%   94, 103, 159, 220-222
crates/a2a-nats-http/src/rest.rs                                                            316     287  9.18%    63-415, 420-425, 427-428, 432-437
crates/a2a-nats-http/src/sse.rs                                                              44      28  36.36%   15-51, 61-68
crates/a2a-nats-http/src/runtime.rs                                                          30      26  13.33%   36-45, 51-147
crates/a2a-nats-http/src/main.rs                                                              4       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/config.rs                                    70       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/cache.rs                                     36       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/mod.rs                                      107       0  100.00%
crates/trogon-decider-runtime/src/event/codec/event_decode.rs                                29       0  100.00%
crates/trogon-decider-runtime/src/event/codec/event_payload_error.rs                         25       0  100.00%
crates/trogon-nats/src/jetstream/create_conflicts.rs                                         24       0  100.00%
crates/trogon-nats/src/jetstream/claim_check.rs                                             393      10  97.46%   45-47, 99-105
crates/trogon-nats/src/jetstream/mocks.rs                                                  1686       1  99.94%   505
crates/trogon-nats/src/jetstream/publish.rs                                                  64       0  100.00%
crates/trogon-nats/src/jetstream/stream_max_age.rs                                           18       0  100.00%
crates/trogon-nats/src/jetstream/traits.rs                                                   46      40  13.04%   181-251
crates/trogon-decider-runtime/src/stream/append_stream.rs                                     5       0  100.00%
crates/trogon-decider-runtime/src/stream/mod.rs                                              38       0  100.00%
crates/trogon-decider-runtime/src/stream/stream_position.rs                                  26       0  100.00%
crates/trogon-decider-runtime/src/stream/read_stream.rs                                       7       0  100.00%
crates/trogon-scheduler/src/telemetry/metrics.rs                                             52       0  100.00%
crates/trogon-scheduler/src/telemetry/trace.rs                                               41       0  100.00%
crates/trogon-std/src/dirs/system.rs                                                         71       0  100.00%
crates/trogon-std/src/dirs/fixed.rs                                                          80       0  100.00%
crates/trogon-std/src/time/mock.rs                                                          125       0  100.00%
crates/trogon-std/src/time/system.rs                                                         31       0  100.00%
crates/trogonai-proto/src/scheduler/schedules/codec.rs                                      377       0  100.00%
crates/trogon-gateway/src/source/microsoft_graph/client_state.rs                             30       0  100.00%
crates/trogon-gateway/src/source/microsoft_graph/server.rs                                  325       0  100.00%
crates/acp-nats/src/jetstream/consumers.rs                                                   91       0  100.00%
crates/acp-nats/src/jetstream/streams.rs                                                    163       4  97.55%   206-208, 218
crates/acp-nats/src/jetstream/ext_policy.rs                                                  26       0  100.00%
crates/acp-nats/src/jetstream/provision.rs                                                   52       0  100.00%
crates/acp-nats/src/nats/extensions.rs                                                        3       0  100.00%
crates/acp-nats/src/nats/mod.rs                                                              23       0  100.00%
crates/acp-nats/src/nats/parsing.rs                                                         278       1  99.64%   151
crates/trogon-std/src/env/system.rs                                                          17       0  100.00%
crates/trogon-std/src/env/in_memory.rs                                                       73       0  100.00%
TOTAL                                                                                     65079    1593  97.55%

Diff against main

Filename                                                         Stmts    Miss  Cover
-------------------------------------------------------------  -------  ------  -------
crates/a2a-auth-callout/src/jwt/mod.rs                               0     -13  +3.96%
crates/a2a-auth-callout/src/credentials/mtls.rs                   +196     +19  +90.31%
crates/a2a-auth-callout/src/credentials/oidc.rs                   +397     +22  +94.46%
crates/a2a-auth-callout/src/credentials/api_key.rs                +121      +6  +95.04%
crates/a2a-auth-callout/src/signing_key_source/key_version.rs        0      -3  +15.00%
TOTAL                                                             +714     +31  -0.02%

Results for commit: 33666d8

Minimum allowed coverage is 95%

♻️ This comment has been updated with latest results

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (6)
rsworkspace/crates/a2a-auth-callout/src/credentials/mod.rs (1)

9-14: 💤 Low value

Consider adding common derives for CredentialSource.

The enum lacks #[derive(Debug, Clone, Copy, PartialEq, Eq)] which are typically expected for simple discriminant enums. These enable logging, pattern matching in tests, and equality comparisons.

Suggested addition
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum CredentialSource {
     Oidc,
     MTls,
     #[deprecated(note = "transitional only; remove after OIDC migration")]
     ApiKey,
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/mod.rs` around lines 9 -
14, The `CredentialSource` enum is missing standard derives that provide common
functionality for simple discriminant enums. Add the derive attribute
`#[derive(Debug, Clone, Copy, PartialEq, Eq)]` before the `pub enum
CredentialSource` declaration to enable logging support, cloning and copying
instances, and equality comparisons needed for testing and pattern matching.
rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs (3)

166-169: 💤 Low value

Redundant Ok(...?) pattern.

Since verify_sync already returns Result<UserJwtClaims, AuthCalloutError>, the Ok(...?) is a no-op.

♻️ Simplify
     async fn verify(&self, cert: &ClientCertPem, account: &AudienceAccount) -> Result<UserJwtClaims, AuthCalloutError> {
         let now = OffsetDateTime::now_utc();
-        Ok(self.verify_sync(cert, account, now)?)
+        self.verify_sync(cert, account, now)
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs` around lines 166
- 169, The verify async function contains a redundant Ok(...?) pattern when
returning the result from verify_sync. Since verify_sync already returns
Result<UserJwtClaims, AuthCalloutError>, the wrapping with Ok() is unnecessary.
Remove the Ok(...?) wrapper and directly return the result from the verify_sync
call using the ? operator, which will properly propagate any errors while
returning the success value as-is.

48-59: ⚡ Quick win

Error context is discarded via string formatting.

Per coding guidelines: "Never discard error context by converting a typed error into a string; wrap the source error as a field or variant instead."

This pattern appears throughout the file (lines 51, 63, 75, 94, 110, 122, 128, 151, 155):

.map_err(|e| AuthCalloutError::CredentialVerification(format!("...: {e}")))

Consider adding structured variants to AuthCalloutError that wrap source errors:

// In error module
pub enum MtlsError {
    PemParse(x509_parser::pem::PemError),
    CertificateParse(x509_parser::error::X509Error),
    SignatureVerification(x509_parser::error::X509Error),
    // ...
}

This preserves the error chain for debugging and allows callers to match on specific failure modes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs` around lines 48
- 59, The function `leaf_der` and other error handling throughout the file are
discarding error context by converting typed errors into strings using format
macros. Instead of using
`AuthCalloutError::CredentialVerification(format!("..."))` pattern, add
structured error variants to the `AuthCalloutError` enum that wrap the source
errors as fields (such as variants for `PemParse`, `CertificateParse`,
`SignatureVerification`, etc.). Then replace all instances of `.map_err()` calls
that use the string formatting pattern with these new structured variants,
ensuring the source error types are preserved in the variant fields for proper
error chain preservation.

Source: Coding guidelines


13-37: 💤 Low value

Consider validating PEM structure at construction or renaming to indicate boundary type.

Per coding guidelines, domain value objects should guarantee correctness at construction. These wrappers currently accept any string and defer validation to verify_sync. Two options:

  1. Validate PEM structure in new() and return Result<Self, ...>
  2. Rename to ClientCertPemInput / TrustAnchorPemInput to signal these are boundary types awaiting conversion

The current approach is functional but blurs the boundary/domain distinction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs` around lines 13
- 37, The ClientCertPem and TrustAnchorPem structs currently accept any string
without validation, blurring the boundary between input and domain types. Choose
one approach: either validate PEM structure in the new() methods of both
ClientCertPem and TrustAnchorPem to return Result<Self, Error> and guarantee
correctness at construction, or rename both structs to ClientCertPemInput and
TrustAnchorPemInput to clearly signal they are boundary types awaiting
validation. Apply the chosen approach consistently across both structs to
properly reflect domain value object semantics.

Source: Coding guidelines

rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs (2)

147-147: 🏗️ Heavy lift

JWKS is fetched on every verification; consider caching.

fetch_jwks() makes an HTTP request to the JWKS endpoint for every token verification when using JwksSource::Remote. JWKS typically changes infrequently (during key rotation). High-traffic scenarios will generate excessive requests and may trigger rate limiting from OIDC providers.

Consider adding JWKS caching with a TTL (e.g., 5-60 minutes) or background refresh.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs` at line 147, The
`fetch_jwks()` method is being called on every token verification without
caching, causing excessive HTTP requests to the JWKS endpoint. Implement a
caching mechanism with a time-to-live (TTL) expiry in the OIDC credentials
structure to store the fetched JWKS. Before calling `fetch_jwks()`, check if a
valid cached JWKS exists within the TTL window (suggested 5-60 minutes). Only
perform the HTTP request if the cache is absent or expired. This will
significantly reduce unnecessary requests while allowing JWKS to be refreshed
after key rotation.

158-163: Explicitly specify allowed algorithms instead of using the JWT header's alg value.

Validation::new(header.alg) configures the validator based on the algorithm claimed in the JWT header. While the jsonwebtoken library does validate that the algorithm matches the key type (an RSA key with HS256 would fail verification), relying on the header's algorithm is not best practice. Explicitly specify the algorithms your system expects (e.g., RS256, RS384, RS512) to follow defense-in-depth principles and avoid potential confusion if library behavior changes.

Suggested fix
-        let mut validation = Validation::new(header.alg);
+        let mut validation = Validation::new(jsonwebtoken::Algorithm::RS256);
+        // Optionally allow RS384, RS512 if needed:
+        // validation.algorithms = vec![
+        //     jsonwebtoken::Algorithm::RS256,
+        //     jsonwebtoken::Algorithm::RS384,
+        //     jsonwebtoken::Algorithm::RS512,
+        // ];
         validation.set_issuer(&[self.issuer.as_str()]);
         validation.set_audience(&auds);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs` around lines 158
- 163, The Validation::new(header.alg) call in the OIDC token verification code
is configuring the JWT validator based on the algorithm claimed in the token
header, which is not a security best practice. Instead of using the header's alg
value, explicitly specify the allowed algorithms that your system expects (such
as RS256, RS384, or RS512) by creating the Validation instance with one of these
explicitly defined algorithms rather than relying on the header value. This
follows defense-in-depth principles and ensures predictable behavior regardless
of any library changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rsworkspace/crates/a2a-auth-callout/src/credentials/api_key.rs`:
- Around line 28-32: The `From<ApiKeyError> for AuthCalloutError` implementation
converts the error to a string using `to_string()`, which loses the original
typed error information. To preserve error context, add a dedicated
`ApiKey(ApiKeyError)` variant to the `AuthCalloutError` enum, then update the
`From` implementation to return `Self::ApiKey(e)` instead of converting to
string via the `CredentialVerification` variant.
- Around line 114-132: The verify method has two error handling inconsistencies
that lose type information. In the registry lookup call, replace the ok_or_else
pattern that constructs a generic CredentialVerification error with a direct
typed error variant like ApiKeyError::Unknown. Similarly, in the
derive_caller_id call, remove the map_err wrapper that converts the error to a
formatted string and instead use the ? operator to propagate the typed error
directly, allowing the From impl to handle the conversion. This ensures
consistent, typed error handling throughout the method.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs`:
- Around line 104-119: The certificate verification loop iterates through
trusted CAs and verifies the leaf certificate's signature but does not validate
that each CA certificate is currently within its validity period. Add a validity
check for each CA certificate in the verification loop (before or after matching
the issuer and verifying the signature) to ensure that expired or not-yet-valid
CA certificates are rejected as trust anchors. This validation should be
performed on each CA in the iteration where leaf.verify_signature is called to
prevent accepting invalid CAs.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs`:
- Around line 84-108: The reqwest::Client built in the OIDC credential
verification code lacks a timeout configuration, which could cause indefinite
hangs if the OIDC discovery or JWKS endpoint becomes unresponsive. Add a timeout
configuration to the Client::builder() chain by calling .timeout() with an
appropriate duration before the .build() call, ensuring that HTTP requests to
the OIDC discovery endpoint and JWKS URI will fail gracefully rather than block
indefinitely.
- Around line 36-45: The `OidcClientId::new` method currently accepts any string
including empty strings, which is inconsistent with `OidcIssuerUrl::parse`
validation. Add validation to the `OidcClientId::new` method to reject empty or
whitespace-only strings and return a Result type (or panic) to enforce that only
valid non-empty client IDs can be created, matching the validation pattern used
in `OidcIssuerUrl::parse`.

---

Nitpick comments:
In `@rsworkspace/crates/a2a-auth-callout/src/credentials/mod.rs`:
- Around line 9-14: The `CredentialSource` enum is missing standard derives that
provide common functionality for simple discriminant enums. Add the derive
attribute `#[derive(Debug, Clone, Copy, PartialEq, Eq)]` before the `pub enum
CredentialSource` declaration to enable logging support, cloning and copying
instances, and equality comparisons needed for testing and pattern matching.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs`:
- Around line 166-169: The verify async function contains a redundant Ok(...?)
pattern when returning the result from verify_sync. Since verify_sync already
returns Result<UserJwtClaims, AuthCalloutError>, the wrapping with Ok() is
unnecessary. Remove the Ok(...?) wrapper and directly return the result from the
verify_sync call using the ? operator, which will properly propagate any errors
while returning the success value as-is.
- Around line 48-59: The function `leaf_der` and other error handling throughout
the file are discarding error context by converting typed errors into strings
using format macros. Instead of using
`AuthCalloutError::CredentialVerification(format!("..."))` pattern, add
structured error variants to the `AuthCalloutError` enum that wrap the source
errors as fields (such as variants for `PemParse`, `CertificateParse`,
`SignatureVerification`, etc.). Then replace all instances of `.map_err()` calls
that use the string formatting pattern with these new structured variants,
ensuring the source error types are preserved in the variant fields for proper
error chain preservation.
- Around line 13-37: The ClientCertPem and TrustAnchorPem structs currently
accept any string without validation, blurring the boundary between input and
domain types. Choose one approach: either validate PEM structure in the new()
methods of both ClientCertPem and TrustAnchorPem to return Result<Self, Error>
and guarantee correctness at construction, or rename both structs to
ClientCertPemInput and TrustAnchorPemInput to clearly signal they are boundary
types awaiting validation. Apply the chosen approach consistently across both
structs to properly reflect domain value object semantics.

In `@rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs`:
- Line 147: The `fetch_jwks()` method is being called on every token
verification without caching, causing excessive HTTP requests to the JWKS
endpoint. Implement a caching mechanism with a time-to-live (TTL) expiry in the
OIDC credentials structure to store the fetched JWKS. Before calling
`fetch_jwks()`, check if a valid cached JWKS exists within the TTL window
(suggested 5-60 minutes). Only perform the HTTP request if the cache is absent
or expired. This will significantly reduce unnecessary requests while allowing
JWKS to be refreshed after key rotation.
- Around line 158-163: The Validation::new(header.alg) call in the OIDC token
verification code is configuring the JWT validator based on the algorithm
claimed in the token header, which is not a security best practice. Instead of
using the header's alg value, explicitly specify the allowed algorithms that
your system expects (such as RS256, RS384, or RS512) by creating the Validation
instance with one of these explicitly defined algorithms rather than relying on
the header value. This follows defense-in-depth principles and ensures
predictable behavior regardless of any library changes.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 167cade7-e0cd-4b91-ad22-033f9e1f6ab6

📥 Commits

Reviewing files that changed from the base of the PR and between f81b933 and 15bb34b.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • rsworkspace/crates/a2a-auth-callout/Cargo.toml
  • rsworkspace/crates/a2a-auth-callout/src/credentials/api_key.rs
  • rsworkspace/crates/a2a-auth-callout/src/credentials/mod.rs
  • rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs
  • rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs
  • rsworkspace/crates/a2a-auth-callout/src/lib.rs

Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/api_key.rs
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/api_key.rs Outdated
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs
- mTLS: refuse CA-bit certs as client end-entity (presenting an
  intermediate / root CA would otherwise pass verification and mint
  claims for the CA subject), and check trust-anchor validity at
  verification time rather than only the leaf.
- OIDC: require the discovery doc's iss to match the configured
  OidcIssuerUrl and constrain jwks_uri to the same origin so a
  tampered/MITM'd discovery response can't redirect us to attacker-
  controlled JWKS. Also bound the reqwest client with a 10s timeout
  and 5s connect deadline so a misbehaving IdP can't hang the
  verifier indefinitely. OidcClientId rejects empty/whitespace input
  to match the other typed value objects.
- API key: ApiKeyVerifier now takes the connection's resolved
  AudienceAccount and refuses keys whose registry audience doesn't
  match — sibling verifiers (mTLS/OIDC) already drive `aud` off the
  connection, so this brings api_key in line and stops a valid key
  from minting for an account the client never requested. ApiKeyError
  gains typed CallerIdDerivation(JwtError) + AudienceMismatch
  variants so the source chain replaces format!() stringification.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs Outdated
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs Outdated
…rigin default ports

- mTLS verification used to bail on the first matching trust anchor whose
  validity check or signature verification failed. During CA rotation that
  rejects valid clients whenever an older anchor is still listed alongside
  the current one. Continue the scan instead so a still-valid sibling
  anchor can vouch for the leaf; only fail when no anchor accepts it.
- OIDC same_origin compared raw port tokens, so 'https://host' vs
  'https://host:443' resolved as different origins and discovery would
  reject a legitimate jwks_uri the IdP just spelled with the default port
  present. Normalize the default ports against the scheme.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2588ca8. Configure here.

Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/oidc.rs
Comment thread rsworkspace/crates/a2a-auth-callout/src/credentials/mtls.rs
…rects in JWKS fetch

- mTLS used to require the leaf's direct issuer to be in the trust
  anchor bundle, which fails the common leaf→intermediate→root setup
  when the bundle only contains the root. Parse every CERTIFICATE
  block in the client PEM as a chain, then walk leaf → intermediates
  → trust anchor at each hop checking validity + signature. The leaf
  end-entity check stays before the walk so a CA bit on the leaf
  still rejects up front.
- OIDC same-origin validation gated `jwks_uri` at discovery, but
  fetch_jwks then used a default reqwest client that follows redirects.
  A same-origin URL could 302 to an attacker host and load malicious
  keys while tokens still claim the configured iss. Disable redirects
  on the client so the IdP must serve JWKS from the same origin
  directly.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
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.

1 participant