feat(a2a-auth-callout): wire production main and add docker-gated integration test - #377
Conversation
yordis
commented
Jun 21, 2026
- Library has been complete since the dispatcher/subscriber slices landed, but the binary was still a stub — operators had no production entrypoint that loaded credential verifiers from the documented environment contract.
- The NATS-server-in-Docker contract was unverified end-to-end against a real auth callout flow; the gated integration test pins it so regressions surface locally where Docker is available without blocking CI.
…egration test The library has been complete since the dispatcher/subscriber slices landed but the binary was still a stub, so operators had no production entrypoint that loaded credential verifiers from the documented environment contract and the NATS-server-in-Docker contract was unverified end-to-end against a real auth callout flow. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
PR SummaryHigh Risk Overview The crate re-exports Adds Docker-gated ( Reviewed by Cursor Bugbot for commit b6920df. Bugbot is set up for automated code reviews on this repo. Configure here. |
|
Warning Review limit reached
More reviews will be available in 31 minutes and 37 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 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughReplaces stub ChangesAuth Callout Production Wiring and Integration Tests
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Code Coverage SummaryDetailsDiff against mainResults for commit: b6920df Minimum allowed coverage is ♻️ This comment has been updated with latest results |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
rsworkspace/crates/a2a-auth-callout/tests/nats_server_callout_integration.rs (1)
202-238: ⚡ Quick winUse the production
Subscriberin this live integration path.This custom loop reimplements the subscriber contract, so the Docker-backed test can pass while production
Subscriber::runregresses around queue subscription, decode-failure fallback replies, publish-failure fallback replies, or denial-reason construction. WiringSubscriber::new(callout_client, capturing, wire).run()here would keep the test aligned with the production path described by the PR objective.♻️ Proposed direction
-use a2a_auth_callout::{ - AccountResolver, AuthCalloutWireCodec, DenialCategory, MintedUserJwt, NkeyPublic, NkeySeed, StaticAccountResolver, -}; +use a2a_auth_callout::{ + AccountResolver, AuthCalloutWireCodec, MintedUserJwt, NkeyPublic, NkeySeed, StaticAccountResolver, Subscriber, +}; - let wire = Arc::new(AuthCalloutWireCodec::new(server_issuer, callout_seed, None, None).expect("wire codec")); + let wire = AuthCalloutWireCodec::new(server_issuer, callout_seed, None, None).expect("wire codec"); let capture = MintedJwtCapture::new(); let dispatch_errors = DispatchErrorCapture::default(); let capturing = CapturingDispatcher { inner: dispatcher, capture: capture.clone(), errors: dispatch_errors.clone(), }; let callout_client = connect_callout_service(&nats_url, client_tls).await; - let mut auth_sub = callout_client - .subscribe("$SYS.REQ.USER.AUTH") - .await - .expect("subscribe auth callout subject"); - let reply_client = callout_client.clone(); - let wire_task = Arc::clone(&wire); - let callout_errors = dispatch_errors.clone(); let subscriber_task = tokio::spawn(async move { - while let Some(msg) = auth_sub.next().await { - ... - } - Ok(()) + Subscriber::new(callout_client, capturing, wire).run().await });🤖 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/tests/nats_server_callout_integration.rs` around lines 202 - 238, The subscriber_task contains a custom reimplementation of the subscription handling logic that diverges from the production Subscriber implementation, which risks masking regressions in queue subscriptions, decode-failure handling, publish-failure handling, or denial-reason construction. Replace the manual while loop that subscribes to "$SYS.REQ.USER.AUTH", handles auth_sub.next().await, and manually encodes/publishes responses with a direct call to the production Subscriber struct by instantiating Subscriber::new(callout_client, capturing, wire) and calling its run() method to keep the test aligned with the actual production code path.
🤖 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/main.rs`:
- Around line 33-45: Create a typed error enum for startup errors instead of
using String-based errors. Update the three functions env_required,
load_nkey_seed_env, and load_nkey_public_env to return this typed error enum
instead of Result<_, String>. Replace the stringly-typed error conversions
(format! and to_string() calls) with enum variants that wrap the source errors
as fields, preserving error context and type information rather than discarding
it through string conversion.
- Around line 92-96: The error message logged when
signing_key_source_from_process_env() fails is misleading because it only
mentions AUTH_CALLOUT_ISSUER being invalid, but the function can fail for
multiple reasons including missing key source mode, vault configuration errors,
or key file access issues. Change the tracing::error message to be more generic
and accurately describe the operation that failed, such as indicating the
failure is in loading or configuring the signing key source, rather than blaming
a specific environment variable.
- Around line 104-108: The current implementation of parsing
AUTH_CALLOUT_USER_JWT_TTL_SECS silently falls back to the default duration when
the value cannot be parsed, which masks configuration errors. Modify the parsing
logic to distinguish between the environment variable being unset (OK to use
default) versus being set but invalid (should fail). Check if the environment
variable exists using std::env::var, and if it returns Ok, attempt to parse the
string value as u64 and Duration; if parsing fails, panic or return an error
rather than defaulting. Only use Duration::from_secs(DEFAULT_USER_JWT_TTL_SECS)
as the default when the environment variable is not set at all (Err case from
std::env::var).
In
`@rsworkspace/crates/a2a-auth-callout/tests/nats_server_callout_integration.rs`:
- Line 19: Add a documentation comment near the async_nats import (line 19) and
at the test harness that uses ConnectOptions with auth callback methods (around
lines 149-159 and 436-454) to explain why async_nats is used directly instead of
the trogon-nats abstraction layer. The comment should clarify that trogon-nats
currently lacks support for dynamic auth callbacks (which are needed for this
test), and this represents an exception to the repo guidelines. Additionally,
consider noting that trogon-nats could be extended in the future to support
callback-based authentication mechanisms for improved testability and
consistency.
- Around line 316-319: The JWKS fixture defines a public key with key_operations
marked as KeyOperations::Sign, but public keys are used for verification, not
signing. In the CommonParameters struct initialization, change the
key_operations field from Some(vec![KeyOperations::Sign]) to
Some(vec![KeyOperations::Verify]) to correctly reflect that this public key is
intended for JWT verification according to RFC 7517 specifications.
---
Nitpick comments:
In
`@rsworkspace/crates/a2a-auth-callout/tests/nats_server_callout_integration.rs`:
- Around line 202-238: The subscriber_task contains a custom reimplementation of
the subscription handling logic that diverges from the production Subscriber
implementation, which risks masking regressions in queue subscriptions,
decode-failure handling, publish-failure handling, or denial-reason
construction. Replace the manual while loop that subscribes to
"$SYS.REQ.USER.AUTH", handles auth_sub.next().await, and manually
encodes/publishes responses with a direct call to the production Subscriber
struct by instantiating Subscriber::new(callout_client, capturing, wire) and
calling its run() method to keep the test aligned with the actual production
code path.
🪄 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: 55ae7457-3f4c-4a4d-a303-d87c6574356d
⛔ Files ignored due to path filters (1)
rsworkspace/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (4)
rsworkspace/crates/a2a-auth-callout/Cargo.tomlrsworkspace/crates/a2a-auth-callout/src/lib.rsrsworkspace/crates/a2a-auth-callout/src/main.rsrsworkspace/crates/a2a-auth-callout/tests/nats_server_callout_integration.rs
…in tests A binary that boots with zero credential verifiers, with a misleading signing-key error message, with a silently defaulted TTL on parse failure, or with String-typed startup errors hides misconfiguration behind a process that looks healthy yet denies every callout. The test JWKS fixture also advertised the public key as 'sign' which is backwards under RFC 7517 and trips verifier libraries that honor key_ops. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…server-nkey TODO The harness mints user JWTs whose audience is the tenant account, but nats.conf only declared AUTH/APP/SYS — without the tenant declared at the server level, even a successful callout cannot land the connect against the intended account. The other Cursor finding is real but requires reading the NATS server's per-boot identity NKey before constructing the wire codec; tracking it inline so the docker-gated flow is honest about its current limitation rather than silently broken. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ 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 f40334f. Configure here.
An Ok(()) return from Subscriber::run means the NATS subscription closed (connection drop or shutdown), which is never a healthy steady state — falling through to a zero exit lets orchestrators treat the silent stop as a clean shutdown and skip the restart, leaving auth callouts down while NATS clients can no longer authenticate. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
