Skip to content

feat: implement draft-hardt-oauth-aauth-protocol across the mesh#472

Merged
yordis merged 29 commits into
mainfrom
yordis/feat-a2a-gateway-aauth-dispatch-wiring
Jul 8, 2026
Merged

feat: implement draft-hardt-oauth-aauth-protocol across the mesh#472
yordis merged 29 commits into
mainfrom
yordis/feat-a2a-gateway-aauth-dispatch-wiring

Conversation

@yordis

@yordis yordis commented Jul 7, 2026

Copy link
Copy Markdown
Member
  • The AAuth verifier merged in feat(a2a-gateway): add AAuth ingress verifier with typed deny reasons #410 was never invoked, so shadow and enforce modes could not observe or protect gateway traffic; verification has to run ahead of the authorization tiers because those tiers assume an authenticated caller.
  • A protocol whose verification side exists but whose issuance, exchange, and authorization roles do not cannot be exercised end to end, let alone rolled out; this implements the remaining draft roles (Person Server, Access Server federation, Agent Provider issuance, agent-side SDK flows, missions, third-party login, delegation) so the three-party flow is provable against real tokens, which the capstone test does.
  • An AAuth layer that is enabled but misconfigured must refuse to start rather than silently run unprotected, matching the precedent set by the tier-1 SpiceDB layer and fix(gateway): fail loudly when enabled integration omits webhook config #457.
  • Denied callers need the aa-resource+jwt challenge on the reply so they can complete the draft's auth-token exchange instead of dead-ending on an opaque error, and a verified person-asserted principal must supersede transport-level caller identity because it is the identity the resource itself challenged for.
  • Key rotation cannot require gateway restarts at fleet scale, so JWKS resolution supports the draft's well-known discovery alongside the static file mode.
  • The NATS binding decisions (AAuth-Auth-Token carriage, -32118, mandatory Content-Digest, explicit nonce) diverge deliberately from the draft's HTTP profile and are recorded in ADR 0017 so they cannot drift silently as the draft evolves.

Known follow-ups, documented in code and ADR: in-memory replay and pending stores are single-node; the PS policy seam cannot yet assert a principal on grant; agent-only access without an auth token is deliberately allowed pending scope policy; SDK HTTP signing sends Signature-Key only, not the full RFC 9421 envelope.

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

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes gateway authentication and caller identity before authorization tiers, with new token verification, JWKS discovery, and deny/challenge behavior on the ingress path—security-critical with a large new surface area.

Overview
Adds ADR 0017 pinning AAuth on NATS (PoP headers, mandatory Content-Digest, AAuth-Auth-Token, JSON-RPC -32118) and implements the rest of the draft-hardt-oauth-aauth-protocol stack as workspace crates (Person Server, Access Server federation, agent SDK, JWKS publisher) with expanded verifier/gateway tests including a three-party capstone.

Gateway: AAuth now runs in dispatch_gateway_ingress before Tier-1–3 policy via env-driven off / shadow / enforce (runtime/aauth_env); misconfiguration fails startup. Enforce denies with full JSON-RPC error wire plus AAuth-Requirement challenges; verified aa-auth+jwt principals override JWT-header caller identity for audit/Tier-1, and successful auth forwards AAuth-Access. Ingress verification also enforces auth scope vs method, mission header/claim binding, and parses capabilities.

Supporting: a2a-nats exposes -32118 ingress error helpers; trogon-aauth-verify gains HTTP JWKS discovery pieces used by static vs well-known GatewayJwksResolver.

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

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds shared AAuth wire types, verifier and SDK libraries, Access Server and Person Server flows, gateway runtime wiring, and JWKS publishing support.

Changes

AAuth platform stack

Layer / File(s) Summary
Shared contracts
rsworkspace/crates/trogon-identity-types/src/aauth/*, rsworkspace/crates/trogon-aauth-as/Cargo.toml, rsworkspace/crates/trogon-aauth-person/Cargo.toml, rsworkspace/crates/trogon-aauth-sdk/Cargo.toml, rsworkspace/crates/trogon-jwks-publisher/Cargo.toml
Adds and extends shared AAuth claim, mission, login, delegation, error, federation, header, and person-server wire types, plus the SDK and AS/PS crate manifests that expose them.
Verifier core
rsworkspace/crates/trogon-aauth-verify/src/*, rsworkspace/crates/trogon-aauth-verify/Cargo.toml
Adds claim, delegation, mission, upstream, request-context, HTTP PoP, JWKS-over-HTTP, and NATS PoP verification logic plus tests and shared re-exports.
Agent SDK and exchange flow
rsworkspace/crates/trogon-aauth-sdk/src/*
Adds agent-side signing, exchange state handling, challenge/response verification, sub-agent helpers, and SDK tests.
Access Server and JWKS publishing
rsworkspace/crates/trogon-aauth-as/src/*, rsworkspace/crates/trogon-jwks-publisher/src/*, rsworkspace/crates/trogon-jwks-publisher/tests/*
Adds the AS token endpoint core, trust/policy/minting/pending state, HTTP routing, and JWKS publishing plus router and roundtrip tests.
Person Server stack
rsworkspace/crates/trogon-aauth-person/src/*, rsworkspace/crates/trogon-aauth-person/tests/*
Adds the PS-side verification, policy, pending, mission, HTTP, interaction, login, minting, and store layers plus end-to-end coverage.
Gateway runtime and routing
rsworkspace/crates/a2a-gateway/src/*, rsworkspace/crates/a2a-nats/src/*, docs/adr/*
Threads AAuth ingress through gateway startup and dispatch, adds the NATS denial response path and header constant, and documents the protocol decisions in ADR 0017.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • TrogonStack/trogonai#410: Both PRs build on the same AAuth ingress verifier layer (a2a-gateway/src/aauth.rs with typed AAuthDenyReason and AAuthIngress::resolve_nats), with the main PR wiring that verifier into runtime/env construction and dispatch denial handling.
  • TrogonStack/trogonai#434: The main PR only updates documentation around tier1_principal_from_caller to reflect AAuth-influenced caller identity, while the retrieved PR actually adds tier1_principal_from_caller/session helpers and wires the live SpiceDB Tier-1 gate, so they overlap on the same Tier-1 principal-construction logic surface.

Suggested labels: rust:coverage-baseline-reset

Poem

A bunny built a token trail,
Through claims and keys and JWKS mail.
Hop, hop — the gateway sees,
Denials, grants, and policy trees.
With headers, missions, signs so bright,
The rabbit binked through day and night. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: implementing the AAuth protocol across the mesh.
Description check ✅ Passed The description is clearly aligned with the PR's AAuth protocol rollout and supporting flows.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/feat-a2a-gateway-aauth-dispatch-wiring

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.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

badge

Code Coverage Summary

Details
Filename                                                                                  Stmts    Miss  Cover    Missing
--------------------------------------------------------------------------------------  -------  ------  -------  -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
crates/a2a-nats/src/nats/subjects/agents/push/list.rs                                        15       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/delete.rs                                      15       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/get.rs                                         12       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/set.rs                                         12       0  100.00%
crates/trogon-scheduler-domain/src/commands/pause_schedule.rs                                31       0  100.00%
crates/trogon-scheduler-domain/src/commands/remove_schedule.rs                               30       0  100.00%
crates/trogon-scheduler-domain/src/commands/create_schedule.rs                               32       0  100.00%
crates/trogon-scheduler-domain/src/commands/state.rs                                         82       0  100.00%
crates/trogon-scheduler-domain/src/commands/resume_schedule.rs                               34       0  100.00%
crates/trogon-scheduler-domain/src/commands/proto_wire.rs                                   138       1  99.28%   231
crates/mcp-nats/src/nats/parsing.rs                                                          98       0  100.00%
crates/mcp-nats/src/nats/mod.rs                                                              23       0  100.00%
crates/trogon-aauth-sdk/src/exchange/challenge.rs                                            50       0  100.00%
crates/trogon-aauth-sdk/src/exchange/mod.rs                                                  17       0  100.00%
crates/trogon-aauth-sdk/src/exchange/core.rs                                                138       0  100.00%
crates/trogon-aauth-sdk/src/exchange/client.rs                                              283       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_signing_secret.rs                     22       0  100.00%
crates/trogon-gateway/src/source/incidentio/server.rs                                        72       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_event_type.rs                         20       0  100.00%
crates/trogon-gateway/src/source/incidentio/signature.rs                                      8       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_server.rs                                 6       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/all_client.rs                                 6       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/one_client.rs                                 9       0  100.00%
crates/trogon-aauth-person/src/login.rs                                                       3       0  100.00%
crates/trogon-aauth-person/src/mint.rs                                                       59       0  100.00%
crates/trogon-aauth-person/src/subagent.rs                                                   10       0  100.00%
crates/trogon-aauth-person/src/interaction.rs                                                 2       0  100.00%
crates/trogon-aauth-person/src/store.rs                                                      21       0  100.00%
crates/trogon-aauth-person/src/agent.rs                                                      84       0  100.00%
crates/trogon-aauth-person/src/error.rs                                                      48       0  100.00%
crates/trogon-aauth-person/src/server.rs                                                    353       0  100.00%
crates/trogon-aauth-person/src/mission.rs                                                    65       0  100.00%
crates/trogon-aauth-person/src/pending.rs                                                    73       0  100.00%
crates/trogon-aauth-person/src/http/mod.rs                                                  213       0  100.00%
crates/trogon-nats/src/lease/renew_interval.rs                                               25       0  100.00%
crates/trogon-nats/src/lease/acquire.rs                                                       5       5  0.00%    9-14
crates/trogon-nats/src/lease/lease_key.rs                                                    19       0  100.00%
crates/trogon-nats/src/lease/lease_timing.rs                                                 15       0  100.00%
crates/trogon-nats/src/lease/release.rs                                                       5       5  0.00%    8-12
crates/trogon-nats/src/lease/renew.rs                                                        82      19  76.83%   23-29, 48-59
crates/trogon-nats/src/lease/mod.rs                                                         107      13  87.85%   113-126
crates/trogon-nats/src/lease/provision.rs                                                    83      10  87.95%   82-92
crates/trogon-nats/src/lease/ttl.rs                                                          27       0  100.00%
crates/trogon-nats/src/lease/nats_kv_lease_config.rs                                         26       0  100.00%
crates/trogon-nats/src/lease/lease_bucket.rs                                                 19       0  100.00%
crates/trogon-scheduler/src/processor/execution/wakeup.rs                                    91       1  98.90%   127
crates/trogon-scheduler/src/processor/execution/checkpoints/store.rs                        145      16  88.97%   103, 121, 125, 132, 224-230, 279-283
crates/trogon-scheduler/src/processor/execution/checkpoints/record.rs                         6       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/failure.rs                       27       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/codec.rs                        318      17  94.65%   340-341, 361-362, 373-377, 405-406, 412-413, 442-443, 480, 485-487
crates/jsonrpc-nats/src/codec/reconstruct.rs                                                 90       5  94.44%   56-59, 91
crates/jsonrpc-nats/src/codec/encode.rs                                                      31       0  100.00%
crates/jsonrpc-nats/src/codec/decode.rs                                                      57       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/go_duration.rs                40       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/recorded_events.rs           241      12  95.02%   200-205, 242, 250, 271, 291, 297, 303, 336, 346, 364, 448
crates/trogon-scheduler/src/processor/execution/reconciliation/request.rs                   230       2  99.13%   285, 290
crates/trogon-scheduler/src/processor/execution/reconciliation/reconcile.rs                 303      13  95.71%   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_key.rs               27       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/schedule_subject.rs           31       0  100.00%
crates/a2a-gateway/src/policy/tier2_cel/evaluator.rs                                        138       0  100.00%
crates/a2a-gateway/src/policy/tier2_cel/compiler.rs                                          25       3  88.00%   61-63
crates/a2a-gateway/src/policy/tier2_cel/bundle.rs                                           120      26  78.33%   70-72, 74-76, 86, 92, 111-113, 123-127, 158, 162-164, 166-168, 171, 178, 181
crates/trogon-scheduler/src/queries/decode.rs                                                95       0  100.00%
crates/trogon-scheduler/src/queries/get_schedule.rs                                           3       0  100.00%
crates/trogon-scheduler/src/queries/schedule_id.rs                                           28       0  100.00%
crates/trogonai-proto/src/codec.rs                                                           16       0  100.00%
crates/trogonai-proto/src/lib.rs                                                             18       0  100.00%
crates/trogonai-proto/src/convert.rs                                                         53       0  100.00%
crates/a2a-identity-types/src/jwt.rs                                                         71       0  100.00%
crates/a2a-identity-types/src/principal.rs                                                   16       0  100.00%
crates/a2a-identity-types/src/caller.rs                                                      24       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_write_text_file.rs                           12       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/terminal_kill.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/session_update.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/client_ops/terminal_wait_for_exit.rs                       12       0  100.00%
crates/a2a-gateway/src/policy/tier1_declarative/bundle.rs                                    57       0  100.00%
crates/a2a-gateway/src/policy/tier1_declarative/evaluator.rs                                158      13  91.77%   24-26, 147, 196-198, 268-272, 295
crates/a2a-gateway/src/policy/tier1_declarative/loader.rs                                    85       9  89.41%   95-97, 99-101, 126-128
crates/a2a-gateway/src/policy/tier1_declarative/time_predicate.rs                           118       2  98.31%   103, 125
crates/a2a-nats/src/server/tasks_cancel.rs                                                   12       0  100.00%
crates/a2a-nats/src/server/message_send.rs                                                   15       0  100.00%
crates/a2a-nats/src/server/push_list.rs                                                      12       0  100.00%
crates/a2a-nats/src/server/tasks_list.rs                                                     12       0  100.00%
crates/a2a-nats/src/server/wire.rs                                                           34       4  88.24%   21-23, 30
crates/a2a-nats/src/server/bridge.rs                                                         65       0  100.00%
crates/a2a-nats/src/server/push_set.rs                                                       12       0  100.00%
crates/a2a-nats/src/server/push_delete.rs                                                    12       0  100.00%
crates/a2a-nats/src/server/tasks_resubscribe.rs                                              12       0  100.00%
crates/a2a-nats/src/server/tasks_get.rs                                                      12       0  100.00%
crates/a2a-nats/src/server/message_stream.rs                                                 56       6  89.29%   155-157, 165-167
crates/a2a-nats/src/server/test_support.rs                                                   81      25  69.14%   134-159
crates/a2a-nats/src/server/agent_card.rs                                                     16       0  100.00%
crates/a2a-nats/src/server/push_get.rs                                                       12       0  100.00%
crates/a2a-nats/src/server/dispatch.rs                                                       33       0  100.00%
crates/a2a-nats/src/server/handler.rs                                                        39       0  100.00%
crates/trogon-decider-sim/src/import_check.rs                                                52       4  92.31%   68-70, 90
crates/trogon-decider-sim/src/session.rs                                                     15       0  100.00%
crates/trogon-decider-sim/src/scenario.rs                                                   142       4  97.18%   152-154, 258
crates/trogon-decider-sim/src/fixture.rs                                                     18       2  88.89%   30-32
crates/trogon-decider-sim/src/host.rs                                                        35       0  100.00%
crates/trogon-gateway/src/source/twitter/config.rs                                            9       0  100.00%
crates/trogon-gateway/src/source/twitter/server.rs                                          144       0  100.00%
crates/trogon-gateway/src/source/twitter/signature.rs                                        16       0  100.00%
crates/trogon-gateway/src/source/datadog/signature.rs                                         7       0  100.00%
crates/trogon-gateway/src/source/datadog/datadog_webhook_token.rs                             9       0  100.00%
crates/trogon-gateway/src/source/datadog/datadog_event_type.rs                               20       0  100.00%
crates/trogon-gateway/src/source/datadog/server.rs                                          108       0  100.00%
crates/ard-registry/src/registry.rs                                                         134       3  97.76%   78, 174, 183
crates/ard-registry/src/router.rs                                                            33       0  100.00%
crates/ard-registry/src/explore_request.rs                                                   30       0  100.00%
crates/ard-registry/src/filters.rs                                                           31       0  100.00%
crates/ard-registry/src/search_filters.rs                                                    28       0  100.00%
crates/ard-registry/src/search_request.rs                                                    32       1  96.88%   43
crates/ard-registry/src/source_url.rs                                                        26       1  96.15%   30
crates/ard-registry/src/extract.rs                                                           12       0  100.00%
crates/ard-registry/src/list_agents_request.rs                                               21       0  100.00%
crates/ard-registry/src/http_error.rs                                                        17       0  100.00%
crates/ard-registry/src/page_token.rs                                                        14       0  100.00%
crates/ard-registry/src/facet_field.rs                                                       13       0  100.00%
crates/ard-registry/src/registry_config.rs                                                   16       0  100.00%
crates/ard-registry/src/lexical_rank.rs                                                      55       2  96.36%   15, 64
crates/trogon-std/src/signal.rs                                                              22      12  45.45%   6-11, 18-25, 34
crates/trogon-std/src/http.rs                                                                 8       0  100.00%
crates/trogon-std/src/uuid.rs                                                                 3       0  100.00%
crates/trogon-std/src/duration.rs                                                            15       0  100.00%
crates/trogon-std/src/args.rs                                                                12       9  25.00%   11-28
crates/trogon-std/src/secret_string.rs                                                       13       0  100.00%
crates/trogon-std/src/json.rs                                                                23       0  100.00%
crates/acp-nats-agent/src/connection.rs                                                     468       1  99.79%   704
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/testing.rs                                                        274       0  100.00%
crates/trogon-decider/src/lib.rs                                                              4       0  100.00%
crates/jsonrpc-nats/src/id.rs                                                                62      20  67.74%   44-61, 81-82, 84-85, 91-92, 98-99, 112
crates/jsonrpc-nats/src/message.rs                                                           11       3  72.73%   37-39
crates/jsonrpc-nats/src/transport.rs                                                         92       1  98.91%   106
crates/a2a-nats/src/nats/subjects/subscriptions/agent_all.rs                                 12       0  100.00%
crates/a2a-nats/src/nats/subjects/subscriptions/task_all_events.rs                            9       0  100.00%
crates/a2a-nats/src/nats/subjects/subscriptions/task_one_events.rs                           12       0  100.00%
crates/trogon-decider/src/event/codec/event_decode.rs                                        13       0  100.00%
crates/trogon-decider/src/event/codec/event_payload_error.rs                                  5       0  100.00%
crates/acp-nats/src/client/terminal_output.rs                                                29       0  100.00%
crates/acp-nats/src/client/test_support.rs                                                   17       0  100.00%
crates/acp-nats/src/client/terminal_create.rs                                                41       0  100.00%
crates/acp-nats/src/client/ext.rs                                                            57       0  100.00%
crates/acp-nats/src/client/mod.rs                                                           101       1  99.01%   56
crates/acp-nats/src/client/fs_write_text_file.rs                                             43       0  100.00%
crates/acp-nats/src/client/ext_session_prompt_response.rs                                    22       0  100.00%
crates/acp-nats/src/client/fs_read_text_file.rs                                              27       0  100.00%
crates/acp-nats/src/client/session_update.rs                                                  2       0  100.00%
crates/acp-nats/src/client/terminal_kill.rs                                                  41       0  100.00%
crates/acp-nats/src/client/terminal_release.rs                                               35       0  100.00%
crates/acp-nats/src/client/terminal_wait_for_exit.rs                                         55       0  100.00%
crates/acp-nats/src/client/rpc_reply.rs                                                     107      43  59.81%   45-47, 61-63, 80-120
crates/acp-nats/src/client/request_permission.rs                                             40       0  100.00%
crates/a2a-nats/src/nats/subjects/stream.rs                                                  50       0  100.00%
crates/trogon-decider-runtime/src/snapshot/mod.rs                                             3       0  100.00%
crates/trogon-decider-runtime/src/snapshot/read_snapshot.rs                                   3       0  100.00%
crates/trogon-decider-runtime/src/snapshot/snapshot_type.rs                                  42       0  100.00%
crates/a2a-nats/src/jetstream/streams.rs                                                      9       0  100.00%
crates/a2a-nats/src/jetstream/stream_options.rs                                              50       0  100.00%
crates/a2a-nats/src/jetstream/consumers.rs                                                   50       0  100.00%
crates/a2a-nats/src/jetstream/provision.rs                                                   16       0  100.00%
crates/mcp-nats-server/src/allowed_host.rs                                                   52       0  100.00%
crates/mcp-nats-server/src/config.rs                                                         58       0  100.00%
crates/mcp-nats-server/src/main.rs                                                            1       1  0.00%    67
crates/mcp-nats-server/src/runtime.rs                                                       268      86  67.91%   146-164, 200-202, 220-221, 232, 265-269, 273-282, 311-319, 324-359, 385-396
crates/a2a-nats/src/catalog/spicedb_permission.rs                                           178      17  90.45%   151-156, 175, 340-344, 373-374, 385-387, 394-396
crates/a2a-nats/src/catalog/store.rs                                                        117       0  100.00%
crates/a2a-nats/src/catalog/watch.rs                                                         18       0  100.00%
crates/a2a-nats/src/catalog/agent_view.rs                                                    47       0  100.00%
crates/a2a-nats/src/catalog/registrar.rs                                                     56       0  100.00%
crates/a2a-nats/src/catalog/nats_kv.rs                                                        8       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/message_send.rs                                     15       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/message_stream.rs                                   15       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/card.rs                                             12       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/mod.rs                                      108       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/client.rs                                    29      15  48.28%   43-69, 97-99, 108-117
crates/a2a-nats/src/catalog/import_gate/spicedb/cache.rs                                     36       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/config.rs                                    70       0  100.00%
crates/a2a-auth-callout/src/credentials/mtls.rs                                             153      13  91.50%   71-72, 168-169, 209-213, 216-219
crates/a2a-auth-callout/src/credentials/oidc.rs                                             188       4  97.87%   212-215
crates/a2a-auth-callout/src/credentials/api_key.rs                                           46       1  97.83%   33
crates/a2a-gateway/src/policy/tier3_redaction/manifest.rs                                    69       3  95.65%   112, 121, 132
crates/a2a-gateway/src/policy/tier3_redaction/decision.rs                                    22       0  100.00%
crates/a2a-gateway/src/policy/tier3_redaction/context.rs                                     40       0  100.00%
crates/a2a-gateway/src/policy/tier3_redaction/mod.rs                                         33       2  93.94%   54, 58
crates/a2a-gateway/src/policy/tier3_redaction/gate.rs                                         3       0  100.00%
crates/a2a-gateway/src/policy/tier3_redaction/json_path.rs                                   84       5  94.05%   37, 49, 85, 104, 115
crates/a2a-gateway/src/policy/tier3_redaction/real_gate.rs                                  138      33  76.09%   18-26, 42-44, 67, 76-80, 119, 148-152, 155-159, 170-174, 192, 265
crates/a2a-gateway/src/policy/tier3_redaction/rewrite.rs                                     49       0  100.00%
crates/acp-nats-stdio/src/config.rs                                                          15       0  100.00%
crates/acp-nats-stdio/src/main.rs                                                            58      11  81.03%   67, 110-117, 123-125, 142
crates/trogon-gateway/src/source/telegram/server.rs                                          53       0  100.00%
crates/trogon-gateway/src/source/telegram/config.rs                                          42       0  100.00%
crates/trogon-gateway/src/source/telegram/registration.rs                                    82       0  100.00%
crates/trogon-gateway/src/source/telegram/signature.rs                                        7       0  100.00%
crates/trogon-std/src/time/mock.rs                                                           32       0  100.00%
crates/trogon-std/src/time/system.rs                                                          9       0  100.00%
crates/trogon-aauth-verify/src/time_source.rs                                                10       0  100.00%
crates/trogon-aauth-verify/src/upstream.rs                                                   20       0  100.00%
crates/trogon-aauth-verify/src/test_support.rs                                               86       0  100.00%
crates/trogon-aauth-verify/src/token.rs                                                     184       1  99.46%   181
crates/trogon-aauth-verify/src/jwks_cache.rs                                                 39       0  100.00%
crates/trogon-aauth-verify/src/jkt.rs                                                        33       0  100.00%
crates/trogon-aauth-verify/src/delegation.rs                                                 53       0  100.00%
crates/trogon-aauth-verify/src/jwks.rs                                                       15       0  100.00%
crates/trogon-aauth-verify/src/jwks_http.rs                                                 144       0  100.00%
crates/trogon-aauth-verify/src/challenge.rs                                                  77       0  100.00%
crates/trogon-aauth-verify/src/mission.rs                                                    33       0  100.00%
crates/trogon-aauth-verify/src/nats_pop.rs                                                  125       1  99.20%   337
crates/trogon-aauth-verify/src/http_pop.rs                                                  268       0  100.00%
crates/trogon-aauth-verify/src/replay.rs                                                     26       0  100.00%
crates/a2a-redaction/src/redactor.rs                                                         32       0  100.00%
crates/a2a-redaction/src/a2a_method.rs                                                       41       0  100.00%
crates/a2a-redaction/src/skill_manifest.rs                                                  310      14  95.48%   139, 169-171, 177, 184-188, 358-360, 452
crates/a2a-redaction/src/skill_id.rs                                                         26       0  100.00%
crates/a2a-redaction/src/wasm_bundle_path.rs                                                 18       0  100.00%
crates/a2a-redaction/src/tier3_sentinel.rs                                                   12       0  100.00%
crates/trogon-gateway/src/source/microsoft_graph/server.rs                                   73       0  100.00%
crates/trogon-gateway/src/source/microsoft_graph/client_state.rs                             14       0  100.00%
crates/trogonai-proto/src/scheduler/schedules/codec.rs                                       57       0  100.00%
crates/a2a-nats-server/src/noop_handler.rs                                                   22       0  100.00%
crates/a2a-nats-server/src/main.rs                                                            1       0  100.00%
crates/a2a-nats-server/src/runtime.rs                                                        17       0  100.00%
crates/trogon-telemetry/src/metric.rs                                                        18       1  94.44%   30
crates/trogon-telemetry/src/service_name.rs                                                  17       0  100.00%
crates/trogon-telemetry/src/trace.rs                                                         15       1  93.33%   24
crates/trogon-telemetry/src/lib.rs                                                          135      23  82.96%   119, 124, 129, 139-140, 146-164, 200, 203, 206, 212
crates/trogon-telemetry/src/resource_attribute.rs                                            13       0  100.00%
crates/trogon-telemetry/src/log.rs                                                           36       0  100.00%
crates/trogon-decider-guest-macros/src/lib.rs                                               121      16  86.78%   14-19, 95-98, 413-422, 426
crates/a2a-auth-callout/src/denial_reason.rs                                                 15       0  100.00%
crates/a2a-auth-callout/src/dispatcher.rs                                                    34      13  61.76%   83-112
crates/a2a-auth-callout/src/account_resolver.rs                                              31       0  100.00%
crates/a2a-auth-callout/src/denial_claims.rs                                                 68       0  100.00%
crates/a2a-auth-callout/src/main.rs                                                           1       1  0.00%    226
crates/a2a-auth-callout/src/permissions.rs                                                   85       0  100.00%
crates/a2a-auth-callout/src/denial_category.rs                                               29       0  100.00%
crates/a2a-auth-callout/src/caller_jwt_header.rs                                             20       0  100.00%
crates/a2a-auth-callout/src/subscriber.rs                                                    96      96  0.00%    27-178
crates/a2a-auth-callout/src/error.rs                                                          3       0  100.00%
crates/a2a-auth-callout/src/test_support.rs                                                  20      20  0.00%    16-36
crates/a2a-redaction/src/signed_bundle/public_key.rs                                         36       2  94.44%   44-45
crates/a2a-redaction/src/signed_bundle/verify.rs                                             64       2  96.88%   90-91
crates/a2a-redaction/src/signed_bundle/manifest.rs                                           56       1  98.21%   83
crates/a2a-redaction/src/signed_bundle/signature.rs                                          30       3  90.00%   37-39
crates/a2a-redaction/src/signed_bundle/digest.rs                                             26       0  100.00%
crates/trogon-scheduler/src/commands/domain/recurrence.rs                                    78       1  98.72%   99
crates/trogon-scheduler/src/commands/domain/schedule_occurrence_sequence.rs                  16       0  100.00%
crates/trogon-service-config/src/lib.rs                                                      38       0  100.00%
crates/trogon-decider-nats/src/store.rs                                                      73      45  38.36%   50-54, 101-167
crates/trogon-decider-nats/src/stream_store.rs                                              267      18  93.26%   70-72, 245, 273-274, 277, 293-297, 464-465, 506, 519-523
crates/trogon-decider-nats/src/snapshot_store.rs                                            446      27  93.95%   208-210, 248-250, 361-367, 449, 585, 590, 686-688, 694-696, 730-731, 741-742, 761, 789-790
crates/a2a-gateway/src/runtime/reply.rs                                                       5       0  100.00%
crates/a2a-gateway/src/runtime/tier1.rs                                                      30       0  100.00%
crates/a2a-gateway/src/runtime/tier1_denial.rs                                               34       1  97.06%   60
crates/a2a-gateway/src/runtime/streaming.rs                                                  35       0  100.00%
crates/a2a-gateway/src/runtime/audit_publish.rs                                              16       0  100.00%
crates/a2a-gateway/src/runtime/aauth_env.rs                                                 162       0  100.00%
crates/a2a-gateway/src/runtime/policy_stack.rs                                               78      31  60.26%   84, 91, 103-112, 119-120, 135-145, 154-170, 175
crates/a2a-gateway/src/runtime/env.rs                                                        55       0  100.00%
crates/a2a-nats/src/audit/task_lifecycle.rs                                                  17       0  100.00%
crates/a2a-nats/src/audit/envelope.rs                                                        57       0  100.00%
crates/a2a-nats/src/audit/emitter.rs                                                         58       0  100.00%
crates/a2a-auth-callout/src/wire/bridge_adapter.rs                                           73       0  100.00%
crates/a2a-auth-callout/src/wire/nkey_public.rs                                              83       3  96.39%   102, 118-119
crates/a2a-auth-callout/src/wire/callout_auth_response_claims.rs                             54       3  94.44%   70-72
crates/a2a-auth-callout/src/wire/nkey_seed.rs                                                20       0  100.00%
crates/a2a-auth-callout/src/wire/wire_codec.rs                                               58       0  100.00%
crates/a2a-auth-callout/src/wire/server_auth_request_claims.rs                              100       4  96.00%   24-26, 127
crates/a2a-auth-callout/src/wire/server_auth_request_envelope.rs                             68       1  98.53%   64
crates/a2a-auth-callout/src/wire/xkey_public.rs                                              23       0  100.00%
crates/a2a-auth-callout/src/wire/test_encode.rs                                              59       0  100.00%
crates/mcp-nats/src/telemetry/transport.rs                                                    6       0  100.00%
crates/a2a-bridge/src/auth.rs                                                                47      15  68.09%   78-99, 148
crates/a2a-bridge/src/nats_transport_harness.rs                                              42       0  100.00%
crates/a2a-bridge/src/main.rs                                                                 1       1  0.00%    199
crates/a2a-bridge/src/identity.rs                                                            63       0  100.00%
crates/a2a-bridge/src/inbound.rs                                                            326      91  72.09%   115-119, 142-144, 191-231, 292-417, 469-471, 482, 580, 631-646, 687-692
crates/a2a-bridge/src/outbound.rs                                                            70       7  90.00%   126, 197-209
crates/a2a-redaction/src/wasm/mod.rs                                                        110       9  91.82%   132-134, 147-149, 162-164
crates/a2a-redaction/src/wasm/engine.rs                                                      62      11  82.26%   46-48, 80-81, 93-95, 99-101
crates/a2a-nats/src/client/resubscribe.rs                                                    28       0  100.00%
crates/a2a-nats/src/client/streaming.rs                                                      73       0  100.00%
crates/a2a-nats/src/client/gateway_headers.rs                                                19       0  100.00%
crates/a2a-nats/src/client/wire.rs                                                           13       0  100.00%
crates/a2a-nats/src/client/unary.rs                                                          39       1  97.44%   57
crates/a2a-nats/src/client/handle.rs                                                        218       0  100.00%
crates/a2a-nats/src/client/error.rs                                                          14       0  100.00%
crates/a2a-nats/src/client/event_stream.rs                                                   76       0  100.00%
crates/trogon-aauth-sdk/src/subagent.rs                                                      34       0  100.00%
crates/trogon-aauth-sdk/src/signer.rs                                                        91       0  100.00%
crates/trogon-aauth-sdk/src/delegation.rs                                                    15       0  100.00%
crates/trogon-aauth-sdk/src/capabilities.rs                                                   7       0  100.00%
crates/trogon-aauth-sdk/src/lib.rs                                                            3       0  100.00%
crates/trogon-aauth-sdk/src/verify_response.rs                                               70       0  100.00%
crates/trogon-gateway/src/source/standard_webhooks.rs                                       138       0  100.00%
crates/a2a-nats/src/catalog/import_gate/principal.rs                                          9       0  100.00%
crates/a2a-nats/src/catalog/import_gate/allow_all.rs                                          2       0  100.00%
crates/ard-registry/src/bin/ard-registry-demo/main.rs                                        64      20  68.75%   13-35
crates/a2a-gateway/src/policy/tier2/mod.rs                                                   46       0  100.00%
crates/a2a-gateway/src/policy/tier2/rule_name.rs                                             19       0  100.00%
crates/a2a-nats/src/push/dispatcher/mod.rs                                                   16       0  100.00%
crates/a2a-nats/src/push/dispatcher/composite.rs                                             15       0  100.00%
crates/a2a-nats/src/push/dispatcher/http.rs                                                  19       0  100.00%
crates/a2a-nats/src/push/dispatcher/jetstream.rs                                             45       0  100.00%
crates/a2a-nats/src/push/dispatcher/nats.rs                                                  37       0  100.00%
crates/a2a-nats/src/nats/subjects/tasks/events.rs                                            17       0  100.00%
crates/trogon-decider-runtime/src/headers/header_map.rs                                      54       0  100.00%
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-identity-types/src/act_chain.rs                                                13       0  100.00%
crates/trogon-gateway/src/source/gitlab/server.rs                                            78       0  100.00%
crates/trogon-gateway/src/source/gitlab/gitlab_signing_token.rs                              30       0  100.00%
crates/trogon-gateway/src/source/gitlab/signature.rs                                         13       0  100.00%
crates/acp-nats/src/lib.rs                                                                   11       0  100.00%
crates/acp-nats/src/req_id.rs                                                                21       0  100.00%
crates/acp-nats/src/wire.rs                                                                  80      14  82.50%   38, 46-60, 103
crates/acp-nats/src/ext_method_name.rs                                                       18       0  100.00%
crates/acp-nats/src/client_proxy.rs                                                          63       1  98.41%   55
crates/acp-nats/src/in_flight_slot_guard.rs                                                   7       0  100.00%
crates/acp-nats/src/config.rs                                                                84       0  100.00%
crates/acp-nats/src/session_id.rs                                                            21       0  100.00%
crates/acp-nats/src/acp_prefix.rs                                                            13       0  100.00%
crates/acp-nats/src/pending_prompt_waiters.rs                                                68       0  100.00%
crates/acp-nats/src/error.rs                                                                 31       0  100.00%
crates/trogon-decider-wit/src/lib.rs                                                         53       1  98.11%   4
crates/a2a-nats/src/req_id.rs                                                                21       0  100.00%
crates/a2a-nats/src/jsonrpc.rs                                                               27       0  100.00%
crates/a2a-nats/src/config.rs                                                               114       0  100.00%
crates/a2a-nats/src/a2a_prefix.rs                                                            16       0  100.00%
crates/a2a-nats/src/gateway_ingress.rs                                                      153      21  86.27%   165-168, 172, 186, 194-200, 233, 248-254
crates/a2a-nats/src/wire.rs                                                                  59       2  96.61%   85, 98
crates/a2a-nats/src/task_id.rs                                                               22       0  100.00%
crates/a2a-nats/src/agent_id.rs                                                              21       0  100.00%
crates/a2a-nats/src/context_id.rs                                                            22       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_encode_error.rs            3       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_encode_error.rs                    16       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/encoded_snapshot.rs                         44       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_decode_error.rs                    19       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_decode_error.rs            6       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_payload_decode.rs                   3       0  100.00%
crates/trogon-nats/src/mocks.rs                                                             224       0  100.00%
crates/trogon-nats/src/messaging.rs                                                         168       2  98.81%   146, 156
crates/trogon-nats/src/server_info.rs                                                        21       3  85.71%   19-21
crates/trogon-nats/src/connect.rs                                                            26       6  76.92%   42-47
crates/trogon-nats/src/client.rs                                                             22      22  0.00%    50-86
crates/trogon-nats/src/auth.rs                                                               45       0  100.00%
crates/trogon-nats/src/nats_token.rs                                                         56       0  100.00%
crates/trogon-nats/src/token.rs                                                               6       0  100.00%
crates/a2a-gateway/src/policy/spicedb_tier1.rs                                              157      13  91.72%   226-228, 381, 451, 453-461
crates/a2a-gateway/src/policy/error.rs                                                       16       0  100.00%
crates/a2a-gateway/src/policy/wasmtime_substrate.rs                                          31       0  100.00%
crates/a2a-gateway/src/policy/per_skill.rs                                                   87       0  100.00%
crates/acp-nats/src/nats/subjects/global/logout.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/ext_notify.rs                                        9       0  100.00%
crates/acp-nats/src/nats/subjects/global/authenticate.rs                                      6       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext.rs                                               9       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/trogon-gateway/src/source/github/config.rs                                             9       0  100.00%
crates/trogon-gateway/src/source/github/signature.rs                                          9       0  100.00%
crates/trogon-gateway/src/source/github/server.rs                                            50       0  100.00%
crates/acp-nats/src/agent/close_session.rs                                                   16       0  100.00%
crates/acp-nats/src/agent/initialize.rs                                                       6       0  100.00%
crates/acp-nats/src/agent/test_support.rs                                                   194       0  100.00%
crates/acp-nats/src/agent/load_session.rs                                                    16       0  100.00%
crates/acp-nats/src/agent/ext_notification.rs                                                12       0  100.00%
crates/acp-nats/src/agent/cancel.rs                                                          12       0  100.00%
crates/acp-nats/src/agent/fork_session.rs                                                    16       0  100.00%
crates/acp-nats/src/agent/set_session_model.rs                                               16       0  100.00%
crates/acp-nats/src/agent/js_request.rs                                                      73       6  91.78%   84-89
crates/acp-nats/src/agent/resume_session.rs                                                  16       0  100.00%
crates/acp-nats/src/agent/prompt.rs                                                         156       7  95.51%   201-207
crates/acp-nats/src/agent/new_session.rs                                                      5       0  100.00%
crates/acp-nats/src/agent/authenticate.rs                                                     5       0  100.00%
crates/acp-nats/src/agent/ext_method.rs                                                      12       0  100.00%
crates/acp-nats/src/agent/bridge.rs                                                         124       4  96.77%   108-111
crates/acp-nats/src/agent/list_sessions.rs                                                    5       0  100.00%
crates/acp-nats/src/agent/logout.rs                                                           5       0  100.00%
crates/acp-nats/src/agent/rpc_call.rs                                                        23       0  100.00%
crates/acp-nats/src/agent/set_session_mode.rs                                                16       0  100.00%
crates/acp-nats/src/agent/set_session_config_option.rs                                       16       0  100.00%
crates/acp-nats/src/jetstream/ext_policy.rs                                                   3       0  100.00%
crates/acp-nats/src/jetstream/consumers.rs                                                   41       0  100.00%
crates/acp-nats/src/jetstream/provision.rs                                                   13       0  100.00%
crates/acp-nats/src/jetstream/streams.rs                                                     18       0  100.00%
crates/ard-catalog/src/catalog_entry_wire.rs                                                  3       0  100.00%
crates/ard-catalog/src/url_or_data.rs                                                        20       0  100.00%
crates/ard-catalog/src/catalog_entry.rs                                                     107       0  100.00%
crates/ard-catalog/src/catalog_manifest.rs                                                   44       0  100.00%
crates/ard-catalog/src/catalog_manifest_schema.rs                                            65       4  93.85%   109-110, 112-113
crates/ard-catalog/src/catalog_manifest_wire.rs                                               3       0  100.00%
crates/ard-catalog/src/trust_manifest.rs                                                     45       1  97.78%   35
crates/ard-catalog/src/metadata.rs                                                           14       0  100.00%
crates/ard-catalog/src/catalog_host_wire.rs                                                   6       0  100.00%
crates/ard-catalog/src/federation_mode.rs                                                     3       0  100.00%
crates/ard-catalog/src/ard_storage_key.rs                                                    10       0  100.00%
crates/ard-catalog/src/display_name.rs                                                       13       0  100.00%
crates/ard-catalog/src/registry_error_wire.rs                                                 8       0  100.00%
crates/ard-catalog/src/catalog_host.rs                                                       26       0  100.00%
crates/ard-catalog/src/ard_identifier.rs                                                     54       0  100.00%
crates/ard-catalog/src/representative_queries.rs                                             18       0  100.00%
crates/ard-catalog/src/media_type.rs                                                         20       0  100.00%
crates/trogon-identity-types/src/aauth/headers.rs                                            47       0  100.00%
crates/trogon-identity-types/src/aauth/mod.rs                                                69       0  100.00%
crates/trogon-identity-types/src/aauth/error.rs                                              14       0  100.00%
crates/trogon-identity-types/src/aauth/login.rs                                              78       0  100.00%
crates/trogon-identity-types/src/aauth/person_server.rs                                      23       0  100.00%
crates/trogon-identity-types/src/aauth/mission.rs                                            33       0  100.00%
crates/a2a-nats-stdio/src/main.rs                                                             1       0  100.00%
crates/a2a-nats-stdio/src/io_loop.rs                                                         49       0  100.00%
crates/a2a-nats-stdio/src/dispatch.rs                                                       207       8  96.14%   116, 119-121, 229, 232-234
crates/a2a-nats-stdio/src/runtime.rs                                                         21       0  100.00%
crates/a2a-nats-stdio/src/wire.rs                                                            22       0  100.00%
crates/trogon-scheduler-domain/src/commands/domain/schedule_event_schedule.rs                35       0  100.00%
crates/trogon-scheduler-domain/src/commands/domain/schedule_event_status.rs                   6       0  100.00%
crates/trogon-scheduler-domain/src/commands/domain/schedule_event_delivery.rs                14       0  100.00%
crates/trogon-scheduler-domain/src/commands/domain/schedule.rs                              383       5  98.69%   326, 334, 349-351
crates/trogon-scheduler-domain/src/commands/domain/schedule_event_sampling_source.rs         11       0  100.00%
crates/trogon-scheduler-domain/src/commands/domain/message.rs                               139       0  100.00%
crates/trogon-scheduler-domain/src/commands/domain/schedule_id.rs                            37       0  100.00%
crates/ard-nats/src/store.rs                                                                  3       0  100.00%
crates/ard-nats/src/catalog_event.rs                                                         71       0  100.00%
crates/ard-nats/src/catalog_index.rs                                                         82       2  97.56%   37, 104
crates/ard-nats/src/catalog_subject.rs                                                       14       3  78.57%   19-21
crates/ard-nats/src/memory_catalog_store.rs                                                  32       0  100.00%
crates/trogon-gateway/src/source/sentry/signature.rs                                          6       0  100.00%
crates/trogon-gateway/src/source/sentry/sentry_client_secret.rs                               9       0  100.00%
crates/trogon-gateway/src/source/sentry/server.rs                                            69       0  100.00%
crates/trogon-scheduler-domain/src/subject.rs                                                26       0  100.00%
crates/trogon-scheduler/src/config.rs                                                        27       0  100.00%
crates/trogon-scheduler/src/error.rs                                                         83      12  85.54%   131-133, 152-154, 159-161, 176-180
crates/trogon-scheduler/src/nats.rs                                                          11       0  100.00%
crates/trogon-scheduler/src/mocks.rs                                                        401      51  87.28%   79, 119-122, 271, 288-291, 333-335, 349-353, 362, 406-410, 462-463, 467, 485-489, 506-509, 552-572
crates/trogon-scheduler/src/queries/read_model/schedule.rs                                   15       0  100.00%
crates/trogon-scheduler/src/queries/read_model/message.rs                                    77       0  100.00%
crates/trogon-scheduler/src/telemetry/trace.rs                                               20       0  100.00%
crates/trogon-scheduler/src/telemetry/metrics.rs                                             27       0  100.00%
crates/a2a-nats-http/src/router.rs                                                           55      13  76.36%   60-63, 69-79
crates/a2a-nats-http/src/headers.rs                                                         129       1  99.22%   159
crates/a2a-nats-http/src/rest.rs                                                            316       8  97.47%   123-126, 282-285
crates/a2a-nats-http/src/sse.rs                                                              44      27  38.64%   15-51, 61-62, 65-68
crates/a2a-nats-http/src/main.rs                                                              1       0  100.00%
crates/a2a-nats-http/src/runtime.rs                                                           8       8  0.00%    60-130
crates/a2a-redaction/src/bin/sign-bundle.rs                                                   1       1  0.00%    163
crates/acp-nats/src/telemetry/metrics.rs                                                     22       0  100.00%
crates/mcp-nats/src/client.rs                                                                12       0  100.00%
crates/mcp-nats/src/transport.rs                                                            263      10  96.20%   244, 256-258, 376-379, 388-389
crates/mcp-nats/src/mcp_prefix.rs                                                            15       0  100.00%
crates/mcp-nats/src/jsonrpc.rs                                                                5       0  100.00%
crates/mcp-nats/src/mcp_peer_id.rs                                                           15       0  100.00%
crates/mcp-nats/src/server.rs                                                                12       0  100.00%
crates/mcp-nats/src/config.rs                                                                59       0  100.00%
crates/mcp-nats/src/wire.rs                                                                  18       0  100.00%
crates/trogon-scheduler/src/processor/execution/worker/processor.rs                         303      12  96.04%   279, 339, 437-438, 444, 499-501, 533-536
crates/trogon-scheduler/src/processor/execution/worker/dispatcher.rs                        280       1  99.64%   200
crates/trogon-scheduler/src/processor/execution/worker/consumer.rs                           77       0  100.00%
crates/trogon-scheduler/src/processor/execution/worker/testkit.rs                           311       4  98.71%   458, 489-490, 495
crates/trogon-std/src/env/in_memory.rs                                                       30       0  100.00%
crates/trogon-std/src/env/system.rs                                                          12       0  100.00%
crates/trogon-std/src/env/enumerate_env.rs                                                    6       0  100.00%
crates/trogon-std/src/env/read_env.rs                                                         3       0  100.00%
crates/trogon-gateway/src/source/discord/config.rs                                           45       0  100.00%
crates/trogon-gateway/src/source/discord/gateway.rs                                         116       1  99.14%   137
crates/trogon-scheduler/src/projections/schedules/storage.rs                                  3       0  100.00%
crates/trogon-scheduler/src/projections/schedules/twin.rs                                    53       0  100.00%
crates/trogon-scheduler/src/projections/schedules/mod.rs                                    175       3  98.29%   708-710
crates/trogon-gateway/src/source/linear/config.rs                                             9       0  100.00%
crates/trogon-gateway/src/source/linear/server.rs                                            83       0  100.00%
crates/trogon-gateway/src/source/linear/signature.rs                                          8       1  87.50%   16
crates/acp-nats/src/nats/subjects/commands/resume.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/set_config_option.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/acp-nats/src/nats/subjects/commands/fork.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_mode.rs                                       15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/prompt.rs                                         15       0  100.00%
crates/a2a-gateway/src/agent_card_surface.rs                                                  3       0  100.00%
crates/a2a-gateway/src/runtime.rs                                                            11       0  100.00%
crates/a2a-gateway/src/main.rs                                                                1       0  100.00%
crates/a2a-gateway/src/audit_ingress.rs                                                     110       0  100.00%
crates/a2a-gateway/src/aauth.rs                                                             285       0  100.00%
crates/a2a-gateway/src/lib.rs                                                                 3       0  100.00%
crates/a2a-gateway/src/config.rs                                                             57       0  100.00%
crates/a2a-gateway/src/jwt_caller_identity.rs                                               151       4  97.35%   165-169, 182-186
crates/a2a-gateway/src/gw_ingress_stream.rs                                                 144       4  97.22%   319-321, 536
crates/a2a-gateway/src/push_dlq_mirror.rs                                                   133      16  87.97%   162-166, 218, 223-226, 236, 261, 382-389
crates/a2a-gateway/src/gw_pull_backpressure.rs                                              209       3  98.56%   504, 704, 717
crates/trogon-aauth-as/src/trust.rs                                                          60       0  100.00%
crates/trogon-aauth-as/src/subagent.rs                                                       10       0  100.00%
crates/trogon-aauth-as/src/http.rs                                                           82       0  100.00%
crates/trogon-aauth-as/src/verify.rs                                                         96       0  100.00%
crates/trogon-aauth-as/src/pending.rs                                                        26       0  100.00%
crates/trogon-aauth-as/src/policy.rs                                                         38       0  100.00%
crates/trogon-aauth-as/src/mint.rs                                                           56       0  100.00%
crates/trogon-aauth-as/src/test_support.rs                                                  122       0  100.00%
crates/trogon-aauth-as/src/server.rs                                                        139       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/one_client.rs                                15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_agent.rs                                 15       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_ext.rs                              9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_session.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/prompt_wildcard.rs                            9       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/resubscribe.rs                                15       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/list.rs                                       15       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/get.rs                                        15       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/cancel.rs                                     15       0  100.00%
crates/acp-nats-server/src/config.rs                                                         39       0  100.00%
crates/acp-nats-server/src/acp_connection_id.rs                                              14       0  100.00%
crates/acp-nats-server/src/main.rs                                                           68       1  98.53%   109
crates/acp-nats-server/src/transport.rs                                                    1020     107  89.51%   242, 290-292, 527, 545, 572, 626, 631, 651, 670, 713-726, 815, 838-840, 892, 909-912, 1008-1011, 1086, 1089, 1092, 1101, 1105, 1108, 1111-1114, 1132, 1165-1168, 1176-1181, 1193-1197, 1201-1210, 1222-1223, 1241-1242, 1252, 1268-1272, 1300-1306, 1326-1328, 1333-1337, 1340-1345, 1362, 1364-1365, 1447-1448, 1460-1461, 1481-1482
crates/acp-nats-server/src/connection.rs                                                    114      35  69.30%   90-97, 102-117, 133, 135-136, 141, 150-151, 156, 160, 164, 167, 175, 179, 182, 185-189
crates/trogon-gateway/src/source_plugin.rs                                                  288       3  98.96%   83, 140-141
crates/trogon-gateway/src/streams.rs                                                          7       0  100.00%
crates/trogon-gateway/src/http.rs                                                            13       0  100.00%
crates/trogon-gateway/src/config.rs                                                        1172      32  97.27%   82, 689, 856, 1003, 1006, 1015, 1101-1108, 1186, 1189, 1198, 1257, 1260, 1344, 1347, 1356, 1421, 1424, 1501, 1504, 1513, 1589, 1592, 1606, 1665, 1668, 1978-1980
crates/trogon-gateway/src/source_integration_id.rs                                           28       2  92.86%   58, 60
crates/trogon-gateway/src/main.rs                                                            26       0  100.00%
crates/trogon-gateway/src/source_status.rs                                                   12       0  100.00%
crates/trogon-decider-wasm-runtime/src/domain_error_detail.rs                                 6       0  100.00%
crates/trogon-decider-wasm-runtime/src/engine.rs                                             43       0  100.00%
crates/trogon-decider-wasm-runtime/src/module_version.rs                                     34       0  100.00%
crates/trogon-decider-wasm-runtime/src/opaque_snapshot.rs                                    18       0  100.00%
crates/trogon-decider-wasm-runtime/src/module_name.rs                                        34       0  100.00%
crates/trogon-decider-wasm-runtime/src/command_type.rs                                       31       0  100.00%
crates/trogon-decider-wasm-runtime/src/execution.rs                                         363       0  100.00%
crates/trogon-decider-wasm-runtime/src/registry.rs                                           28       0  100.00%
crates/trogon-decider-wasm-runtime/src/command_spec.rs                                       12       0  100.00%
crates/trogon-decider-wasm-runtime/src/snapshot_id.rs                                        15       0  100.00%
crates/trogon-decider-wasm-runtime/src/module.rs                                             64       0  100.00%
crates/trogon-decider-wasm-runtime/src/test_fixture.rs                                        7       0  100.00%
crates/trogon-nats/src/jetstream/claim_check.rs                                             104       3  97.12%   46-48
crates/trogon-nats/src/jetstream/publish.rs                                                  30       0  100.00%
crates/trogon-nats/src/jetstream/stream_max_age.rs                                            8       0  100.00%
crates/trogon-nats/src/jetstream/traits.rs                                                   46      40  13.04%   181-251
crates/trogon-nats/src/jetstream/create_conflicts.rs                                         14       0  100.00%
crates/trogon-nats/src/jetstream/mocks.rs                                                   941       1  99.89%   507
crates/trogon-decider-runtime/src/execution.rs                                              379       0  100.00%
crates/acp-nats/src/nats/subjects/stream.rs                                                  56       0  100.00%
crates/trogon-nats/src/telemetry/messaging.rs                                                37       0  100.00%
crates/mcp-nats-stdio/src/config.rs                                                          26       0  100.00%
crates/mcp-nats-stdio/src/main.rs                                                            36       0  100.00%
crates/mcp-nats/src/nats/subjects/client/create_message.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/progress.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/roots_list_changed.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/create_elicitation.rs                               12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/initialized.rs                                      12       0  100.00%
crates/trogon-gateway/src/source/notion/notion_event_type.rs                                 20       0  100.00%
crates/trogon-gateway/src/source/notion/notion_verification_token.rs                          9       0  100.00%
crates/trogon-gateway/src/source/notion/signature.rs                                          9       0  100.00%
crates/trogon-gateway/src/source/notion/verification_token.rs                                46       0  100.00%
crates/trogon-gateway/src/source/notion/server.rs                                           120       4  96.67%   116-117, 136-137
crates/trogon-jwks-publisher/src/publisher.rs                                                92       0  100.00%
crates/trogon-jwks-publisher/src/provider.rs                                                118       0  100.00%
crates/trogon-decider-runtime/src/event/stream_event.rs                                       8       0  100.00%
crates/trogon-decider-runtime/src/event/event_identity.rs                                     3       0  100.00%
crates/trogon-decider-runtime/src/event/event_id.rs                                          32       0  100.00%
crates/acp-nats/src/nats/parsing.rs                                                         113      15  86.73%   138-152, 192
crates/acp-nats/src/nats/jsonrpc.rs                                                          51      11  78.43%   46, 54-55, 57-63, 81-83
crates/acp-nats/src/nats/mod.rs                                                              61      13  78.69%   22-33, 75
crates/acp-nats/src/nats/extensions.rs                                                        3       0  100.00%
crates/trogon-scheduler/src/commands/record_schedule_occurrence.rs                          113       1  99.12%   182
crates/trogon-scheduler/src/commands/schedule_next_occurrence.rs                             74       0  100.00%
crates/a2a-nats-http/src/handlers/mod.rs                                                    185      12  93.51%   68, 88-91, 121, 155, 169-172, 185
crates/trogon-gateway/src/source/slack/server.rs                                            272       0  100.00%
crates/trogon-gateway/src/source/slack/socket_mode.rs                                       139       0  100.00%
crates/trogon-gateway/src/source/slack/signature.rs                                          17       0  100.00%
crates/trogon-gateway/src/source/slack/config.rs                                             32       0  100.00%
crates/trogon-std/src/telemetry/http.rs                                                      58       0  100.00%
crates/trogon-scheduler/src/processor/execution/execution_schedules/mod.rs                   82       0  100.00%
crates/a2a-auth-callout/src/signing_key_source/static_source.rs                              25       0  100.00%
crates/a2a-auth-callout/src/signing_key_source/vault.rs                                       3       0  100.00%
crates/a2a-auth-callout/src/signing_key_source/env.rs                                        40       0  100.00%
crates/a2a-auth-callout/src/signing_key_source/key_version.rs                                16       0  100.00%
crates/a2a-auth-callout/src/signing_key_source/loader.rs                                     23       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       0  100.00%
crates/a2a-auth-callout/src/signing_key_source/signing_key_handle.rs                         15       0  100.00%
crates/a2a-pack/src/agent_card_schema.rs                                                     40       0  100.00%
crates/a2a-pack/src/resource_tuples.rs                                                      152       0  100.00%
crates/a2a-pack/src/agent_card_read.rs                                                       23       0  100.00%
crates/acp-nats/src/nats/subjects/responses/ext_ready.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/prompt_response.rs                               20       0  100.00%
crates/acp-nats/src/nats/subjects/responses/response.rs                                      20       0  100.00%
crates/acp-nats/src/nats/subjects/responses/update.rs                                        20       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/unsubscribe_resource.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/logging_message.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/get_task_result.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/list_tools.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_prompt.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/progress.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/cancelled.rs                                        12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_prompts.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/list_resource_templates.rs                          12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/ping.rs                                              9       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/complete.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/prompt_list_changed.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/subscribe_resource.rs                               12       0  100.00%
crates/trogon-std/src/fs/mem.rs                                                              85       0  100.00%
crates/trogon-std/src/fs/system.rs                                                           15       0  100.00%
crates/trogon-std/src/dirs/fixed.rs                                                          32       0  100.00%
crates/trogon-std/src/dirs/system.rs                                                         39       0  100.00%
crates/a2a-bridge/src/auth/callout_mint.rs                                                   49       1  97.96%   94
crates/a2a-auth-callout/src/jwt/nats_user_jwt.rs                                            187       1  99.47%   131
crates/a2a-auth-callout/src/jwt/user_jwt_subject.rs                                          12       0  100.00%
crates/a2a-auth-callout/src/jwt/nats_permission_claims.rs                                    10       0  100.00%
crates/a2a-auth-callout/src/jwt/mod.rs                                                      232       0  100.00%
crates/a2a-nats/src/push/push_notification_config.rs                                          6       0  100.00%
crates/a2a-nats/src/push/terminal_push_task_state.rs                                         17       0  100.00%
crates/a2a-nats/src/push/caller_id.rs                                                        41       0  100.00%
crates/a2a-nats/src/push/idempotency_key_header.rs                                           16       0  100.00%
crates/a2a-nats/src/push/push_notification_target.rs                                         32       0  100.00%
crates/a2a-nats/src/push/dlq.rs                                                              56       0  100.00%
crates/a2a-nats/src/push/dispatch_error.rs                                                   24       0  100.00%
crates/a2a-nats/src/push/authentication_header.rs                                            31       0  100.00%
crates/a2a-nats/src/push/push_delivery_semantics_registry.rs                                 17       0  100.00%
crates/a2a-nats/src/push/push_idempotency_key.rs                                             43       0  100.00%
crates/a2a-nats/src/push/dlq_dedup.rs                                                        51       1  98.04%   79
crates/a2a-nats/src/push/status_transition_id.rs                                             15       0  100.00%
crates/a2a-nats/src/push/delivery_semantics.rs                                               98       0  100.00%
crates/a2a-nats/src/push/target.rs                                                           19       0  100.00%
crates/a2a-nats/src/push/nats_push_subject.rs                                                12       0  100.00%
crates/a2a-nats/src/push/push_notification_config_id.rs                                      17       0  100.00%
crates/a2a-nats/src/push/push_payload.rs                                                     18       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/codec/twin.rs                    96       0  100.00%
crates/trogon-decider-runtime/src/stream/append_stream.rs                                     5       0  100.00%
crates/trogon-decider-runtime/src/stream/read_stream.rs                                       7       0  100.00%
crates/trogon-decider-runtime/src/stream/stream_position.rs                                  26       0  100.00%
TOTAL                                                                                     36757    1583  95.69%

Diff against main

Filename                                                   Stmts    Miss  Cover
-------------------------------------------------------  -------  ------  --------
crates/trogon-aauth-sdk/src/exchange/challenge.rs            +50       0  +100.00%
crates/trogon-aauth-sdk/src/exchange/mod.rs                  +17       0  +100.00%
crates/trogon-aauth-sdk/src/exchange/core.rs                +138       0  +100.00%
crates/trogon-aauth-sdk/src/exchange/client.rs              +283       0  +100.00%
crates/trogon-aauth-person/src/login.rs                       +3       0  +100.00%
crates/trogon-aauth-person/src/mint.rs                       +59       0  +100.00%
crates/trogon-aauth-person/src/subagent.rs                   +10       0  +100.00%
crates/trogon-aauth-person/src/interaction.rs                 +2       0  +100.00%
crates/trogon-aauth-person/src/store.rs                      +21       0  +100.00%
crates/trogon-aauth-person/src/agent.rs                      +84       0  +100.00%
crates/trogon-aauth-person/src/error.rs                      +48       0  +100.00%
crates/trogon-aauth-person/src/server.rs                    +353       0  +100.00%
crates/trogon-aauth-person/src/mission.rs                    +65       0  +100.00%
crates/trogon-aauth-person/src/pending.rs                    +73       0  +100.00%
crates/trogon-aauth-person/src/http/mod.rs                  +213       0  +100.00%
crates/trogon-aauth-verify/src/upstream.rs                   +20       0  +100.00%
crates/trogon-aauth-verify/src/token.rs                      +36       0  +0.13%
crates/trogon-aauth-verify/src/delegation.rs                 +53       0  +100.00%
crates/trogon-aauth-verify/src/jwks_http.rs                 +144       0  +100.00%
crates/trogon-aauth-verify/src/challenge.rs                  +32       0  +100.00%
crates/trogon-aauth-verify/src/mission.rs                    +33       0  +100.00%
crates/trogon-aauth-verify/src/nats_pop.rs                     0      -1  +0.80%
crates/trogon-aauth-verify/src/http_pop.rs                  +268       0  +100.00%
crates/a2a-gateway/src/runtime/aauth_env.rs                 +162       0  +100.00%
crates/trogon-aauth-sdk/src/subagent.rs                      +34       0  +100.00%
crates/trogon-aauth-sdk/src/signer.rs                        +91       0  +100.00%
crates/trogon-aauth-sdk/src/delegation.rs                    +15       0  +100.00%
crates/trogon-aauth-sdk/src/capabilities.rs                   +7       0  +100.00%
crates/trogon-aauth-sdk/src/lib.rs                            +3       0  +100.00%
crates/trogon-aauth-sdk/src/verify_response.rs               +70       0  +100.00%
crates/a2a-nats/src/gateway_ingress.rs                        +7       0  +0.66%
crates/trogon-identity-types/src/aauth/headers.rs            +47       0  +100.00%
crates/trogon-identity-types/src/aauth/mod.rs                 +9      -4  +6.67%
crates/trogon-identity-types/src/aauth/error.rs              +14       0  +100.00%
crates/trogon-identity-types/src/aauth/login.rs              +78       0  +100.00%
crates/trogon-identity-types/src/aauth/person_server.rs      +23       0  +100.00%
crates/trogon-identity-types/src/aauth/mission.rs            +33       0  +100.00%
crates/a2a-gateway/src/aauth.rs                              +86      -5  +2.51%
crates/trogon-aauth-as/src/trust.rs                          +60       0  +100.00%
crates/trogon-aauth-as/src/subagent.rs                       +10       0  +100.00%
crates/trogon-aauth-as/src/http.rs                           +82       0  +100.00%
crates/trogon-aauth-as/src/verify.rs                         +96       0  +100.00%
crates/trogon-aauth-as/src/pending.rs                        +26       0  +100.00%
crates/trogon-aauth-as/src/policy.rs                         +38       0  +100.00%
crates/trogon-aauth-as/src/mint.rs                           +56       0  +100.00%
crates/trogon-aauth-as/src/test_support.rs                  +122       0  +100.00%
crates/trogon-aauth-as/src/server.rs                        +139       0  +100.00%
crates/trogon-jwks-publisher/src/publisher.rs                +92       0  +100.00%
crates/trogon-jwks-publisher/src/provider.rs                +118       0  +100.00%
TOTAL                                                      +3523     -10  +0.49%

Results for commit: 7d78847

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: 3

🧹 Nitpick comments (2)
rsworkspace/crates/a2a-nats/src/gateway_ingress.rs (1)

237-245: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider exporting -32_118 as a named constant.

The literal is duplicated in a2a-gateway's dispatch audit code (AuditOutcome::Err { code: -32_118, ... }). Exporting it here (mirroring a2a_gateway::aauth::AAUTH_REQUIRED_CODE as the doc states) and having dispatch.rs reference it would eliminate the drift risk between the two crates.

♻️ Proposed constant export
+/// Mirrors `a2a_gateway::aauth::AAUTH_REQUIRED_CODE`.
+pub const AAUTH_DENIED_CODE: i32 = -32_118;
+
 pub fn ingress_gateway_aauth_denied_response_bytes(
     request_headers: &HeaderMap,
     request_payload_hint: &[u8],
     message: impl Into<String>,
 ) -> Result<bytes::Bytes, WireError> {
-    Ok(ingress_error_wire(request_headers, request_payload_hint, -32_118, message, None)?.body)
+    Ok(ingress_error_wire(request_headers, request_payload_hint, AAUTH_DENIED_CODE, message, None)?.body)
 }
#!/bin/bash
# Confirm the AAUTH_REQUIRED_CODE constant this comment claims to mirror.
rg -n 'AAUTH_REQUIRED_CODE' rsworkspace/crates/a2a-gateway
🤖 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-nats/src/gateway_ingress.rs` around lines 237 - 245,
The AAUTH denial status code is hardcoded in
ingress_gateway_aauth_denied_response_bytes and duplicated elsewhere, so it
should be exported as a named constant instead of using the literal. Introduce a
shared constant near ingress_gateway_aauth_denied_response_bytes in a2a-nats
(mirroring a2a_gateway::aauth::AAUTH_REQUIRED_CODE) and update dispatch.rs in
a2a-gateway to reference that constant so both crates stay aligned.
rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs (1)

296-302: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded -32_118 duplicates the code baked into ingress_gateway_aauth_denied_response_bytes.

If the canonical AAUTH_REQUIRED_CODE referenced in a2a-nats's doc comment ever changes, this audit literal can silently drift out of sync. See companion comment in gateway_ingress.rs suggesting an exported constant to reference from here instead.

🤖 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-gateway/src/runtime/dispatch.rs` around lines 296 -
302, The audit outcome in dispatch.rs hardcodes the AAUTH rejection code, which
can drift from the canonical value used by ingress response handling. Update the
code path around the AuditOutcome::Err in dispatch to reference a shared
exported AAUTH_REQUIRED_CODE constant from the gateway ingress/aauth module
instead of repeating the numeric literal, so dispatch.rs and
ingress_gateway_aauth_denied_response_bytes stay in sync.
🤖 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-gateway/src/runtime/aauth_env.rs`:
- Around line 187-205: Both optional_u64 and optional_i64 are discarding the
ParseIntError from .parse(), so the resulting AAuthEnvError loses useful
diagnostics. Update the AAuthEnvError variant used here to carry the parse error
as a #[source] field, and change both helpers to pass through the original error
instead of mapping it to an underscore. Keep the raw input in the error too, but
preserve the typed source from the parse call for better overflow/invalid-digit
reporting.
- Around line 152-157: The required_var helper in aauth_env.rs accepts non-empty
env values but returns them untrimmed, so trailing newlines from secret-mounted
files can leak into callers like jwks_path, challenge_key_path, resource_iss,
person_server_aud, and challenge_kid. Update required_var to normalize the value
before returning it, keeping the existing empty-check but returning the trimmed
string instead of the original. Make sure AAuthEnvError::MissingRequired
behavior stays the same for blank values.
- Around line 97-111: The `NonNegativeSecs::new` error path in `aauth_env.rs` is
discarding the typed validation error and re-reading the env var via
`env.var(...)`. Update the parsing flow around `optional_i64`,
`NonNegativeSecs::new`, and the `AAuthEnvError::InvalidNonNegativeSecs` mapping
so the raw value is captured once and reused. Preserve the original
`NonNegativeSecs` error as a source field or variant instead of converting it
away, and avoid the extra env lookup in both `challenge_ttl_secs` and
`max_skew_secs`.

---

Nitpick comments:
In `@rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs`:
- Around line 296-302: The audit outcome in dispatch.rs hardcodes the AAUTH
rejection code, which can drift from the canonical value used by ingress
response handling. Update the code path around the AuditOutcome::Err in dispatch
to reference a shared exported AAUTH_REQUIRED_CODE constant from the gateway
ingress/aauth module instead of repeating the numeric literal, so dispatch.rs
and ingress_gateway_aauth_denied_response_bytes stay in sync.

In `@rsworkspace/crates/a2a-nats/src/gateway_ingress.rs`:
- Around line 237-245: The AAUTH denial status code is hardcoded in
ingress_gateway_aauth_denied_response_bytes and duplicated elsewhere, so it
should be exported as a named constant instead of using the literal. Introduce a
shared constant near ingress_gateway_aauth_denied_response_bytes in a2a-nats
(mirroring a2a_gateway::aauth::AAUTH_REQUIRED_CODE) and update dispatch.rs in
a2a-gateway to reference that constant so both crates stay aligned.
🪄 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: d0c69d62-9029-4efd-9cf8-e7c6981d5e1c

📥 Commits

Reviewing files that changed from the base of the PR and between 7fb9298 and e1637e4.

📒 Files selected for processing (8)
  • rsworkspace/crates/a2a-gateway/src/runtime.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env/tests.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs
  • rsworkspace/crates/a2a-nats/src/gateway_ingress.rs
  • rsworkspace/crates/a2a-nats/src/gateway_ingress/tests.rs
  • rsworkspace/crates/a2a-nats/src/lib.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/headers.rs

Comment thread rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs Outdated
Comment thread rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
Comment thread rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
yordis added 8 commits July 7, 2026 06:22
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…g draft verification rules

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…wn jwks publishing

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…ty, enforce scopes and missions

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis changed the title feat(a2a-gateway): wire aauth ingress verification into gateway dispatch feat: implement draft-hardt-oauth-aauth-protocol across the mesh Jul 7, 2026
Comment thread rsworkspace/crates/a2a-gateway/src/aauth.rs Outdated
Comment thread rsworkspace/crates/a2a-gateway/src/aauth.rs
Comment thread rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs Outdated
…ect negative jwks ttl

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

@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: 19

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (4)
rsworkspace/crates/trogon-aauth-as/src/subagent.rs-36-45 (1)

36-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

BadShape check doesn't actually enforce three segments.

splitn(3, '.') combined with only two parts.next() calls accepts a two-segment string like "header.payload" (no signature segment) without error, even though the doc/error text says "expected three dot-separated segments." In practice this is low-risk since callers only pass already-signature-verified JWTs (which structurally must have 3 segments), but the shape check itself doesn't match its own contract.

🐛 Proposed fix to actually check for three segments
     let mut parts = verified_jwt.splitn(3, '.');
     let _header = parts.next().ok_or(ParentAgentError::BadShape)?;
     let payload_b64 = parts.next().ok_or(ParentAgentError::BadShape)?;
+    if parts.next().is_none() {
+        return Err(ParentAgentError::BadShape);
+    }
     let payload = URL_SAFE_NO_PAD
🤖 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/trogon-aauth-as/src/subagent.rs` around lines 36 - 45, The
shape validation in parent_agent_of only consumes two split segments, so it can
accept a token with no signature segment even though BadShape implies three
dot-separated parts. Update the parsing in parent_agent_of to explicitly verify
that the JWT has exactly three segments before decoding the payload, and keep
the existing ParentAgentError::BadShape path for any malformed input.
rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs-234-239 (1)

234-239: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Reject negative JWKS TTLs here. A negative A2A_GATEWAY_AAUTH_JWKS_TTL_SECS makes every cached JWK entry expire immediately, so discovery stops caching and re-fetches on every verification. Clamp or validate this at env parsing.

🤖 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-gateway/src/runtime/aauth_env.rs` around lines 234 -
239, The JWKS TTL parsing in well_known_resolver_from_env currently accepts
negative values from optional_i64, which causes CachedJwksResolver to
effectively disable caching; validate or clamp ENV_AAUTH_JWKS_TTL_SECS to a
non-negative value before passing it into
CachedJwksResolver::new(...).with_ttl_secs(...), and return an AAuthEnvError if
the env value is negative so the bad configuration is rejected early.
rsworkspace/crates/trogon-aauth-sdk/src/subagent.rs-54-56 (1)

54-56: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Decode errors are silently discarded, conflating malformed tokens with "not a sub-agent token".

decode_payload drops the underlying base64/serde_json error via map_err(|_| ...), and parent_agent_of further swallows any decode failure into None. As a result, build_subagent_token_request reports NotASubAgentToken for a genuinely malformed subagent_agent_jwt, hiding the real cause. As per coding guidelines, **/*.rs: "Never discard error context by converting a typed error into a string; wrap the source error as a field or variant instead."

🩹 Proposed fix to preserve error context
 pub enum SubAgentError {
     ...
     /// The agent token's payload segment could not be decoded as JSON.
-    #[error("agent token payload could not be decoded")]
-    MalformedAgentToken,
+    #[error("agent token payload could not be decoded: {0}")]
+    MalformedAgentToken(String),
 }

 fn decode_payload(jwt: &str) -> Result<ParentAgentOnly, SubAgentError> {
     let mut parts = jwt.splitn(3, '.');
     let _ = parts.next();
-    let payload_b64 = parts.next().ok_or(SubAgentError::MalformedAgentToken)?;
+    let payload_b64 = parts
+        .next()
+        .ok_or_else(|| SubAgentError::MalformedAgentToken("missing payload segment".into()))?;
     let payload = URL_SAFE_NO_PAD
         .decode(payload_b64.as_bytes())
-        .map_err(|_| SubAgentError::MalformedAgentToken)?;
-    serde_json::from_slice(&payload).map_err(|_| SubAgentError::MalformedAgentToken)
+        .map_err(|e| SubAgentError::MalformedAgentToken(e.to_string()))?;
+    serde_json::from_slice(&payload).map_err(|e| SubAgentError::MalformedAgentToken(e.to_string()))
 }

Then have build_subagent_token_request propagate decode_payload's Result directly for subagent_agent_jwt instead of routing through parent_agent_of's Option, so malformed input surfaces as MalformedAgentToken rather than NotASubAgentToken.

Also applies to: 64-72, 106-116

🤖 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/trogon-aauth-sdk/src/subagent.rs` around lines 54 - 56,
Decode failures in parent_agent_of are being collapsed into None, which hides
malformed token errors and turns them into NotASubAgentToken. Update
parent_agent_of and the decode_payload flow in subagent.rs to preserve and
propagate the underlying decode error instead of discarding it, and make
build_subagent_token_request return the decode failure directly for
subagent_agent_jwt so malformed input surfaces as MalformedAgentToken. Keep the
error context attached in the typed error path rather than converting it to a
string or Option.

Source: Coding guidelines

rsworkspace/crates/trogon-aauth-verify/src/mission.rs-13-16 (1)

13-16: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the doc link to MissionRef
The module docs link to [MissionClaim], but this crate uses MissionRef here, so rustdoc will emit a broken intra-doc link warning.

🤖 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/trogon-aauth-verify/src/mission.rs` around lines 13 - 16,
The module docs contain a broken intra-doc link because they refer to
MissionClaim, but this crate actually uses MissionRef in this context. Update
the doc comment near extract_mission_claim and AuthClaims to point the link at
MissionRef so rustdoc resolves it correctly and the documentation stays
consistent with the types used here.
🧹 Nitpick comments (20)
rsworkspace/crates/trogon-aauth-sdk/Cargo.toml (1)

26-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant trogon-aauth-verify dev-dependency.

It's already listed under [dependencies] (line 26) with identical workspace = true, making the [dev-dependencies] re-declaration (line 33) redundant since regular dependencies are already available to tests.

♻️ Proposed fix
 [dev-dependencies]
 jsonwebtoken = { version = "=10.4.0", features = ["rust_crypto"] }
 tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros", "time"] }
-trogon-aauth-verify = { workspace = true }
 wiremock = { workspace = true }
🤖 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/trogon-aauth-sdk/Cargo.toml` around lines 26 - 34, Remove
the redundant test-only re-declaration of trogon-aauth-verify in Cargo.toml for
trogon-aauth-sdk, since it is already available through the existing
[dependencies] entry with workspace = true. Keep the dependency only once in the
manifest and leave the other dev-dependencies unchanged; use the
trogon-aauth-verify and [dev-dependencies] entries to locate the duplicate.
rsworkspace/crates/trogon-identity-types/src/aauth/mission.rs (1)

106-129: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuses hand-rolled parsing instead of shared split_header helper.

Requirement::parse in mod.rs uses split_header and tolerates malformed segments gracefully; MissionHeader::parse re-implements similar key="value"; key="value" parsing but bails entirely (?) on any single malformed segment. Consider factoring both onto a shared helper for consistent behavior and to avoid parsing-logic duplication.

🤖 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/trogon-identity-types/src/aauth/mission.rs` around lines
106 - 129, MissionHeader::parse is duplicating header parsing logic instead of
using the shared split_header helper used by Requirement::parse, and it
currently aborts on any malformed segment rather than handling invalid parts
consistently. Update MissionHeader::parse in mission.rs to reuse split_header
(or factor both parsers onto a common helper) so parsing behavior matches the
existing tolerant approach, while still extracting approver and s256 from the
parsed segments.
rsworkspace/crates/trogon-jwks-publisher/src/publisher.rs (2)

116-168: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Dwk filenames stored as raw String rather than a validated domain type.

JwksPublisherConfigBuilder::entries and JwksPublisherConfig::entries key on raw String, with correctness enforced only inside with_jwk_set at call time. Per this repo's coding guideline to prefer domain-specific value objects over primitives so invalid instances are unrepresentable, consider a DwkFilename (or similar) enum/newtype with a fallible constructor (TryFrom<&str>), used as the HashMap key and as the Path extractor type in serve_dwk. That would let the type system (rather than a runtime check duplicated per call site) guarantee only the four registered filenames are ever handled.

🤖 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/trogon-jwks-publisher/src/publisher.rs` around lines 116 -
168, The builder and config currently store dwk names as raw String keys, so
validity is only checked at insertion time in
JwksPublisherConfigBuilder::with_jwk_set. Introduce a domain-specific
DwkFilename newtype/enum with a fallible constructor and use it in
JwksPublisherConfigBuilder::entries, JwksPublisherConfig::entries, and the
serve_dwk path extractor so only valid registered filenames can exist by type.
Keep the existing uniqueness and known-dwk checks at the conversion boundary,
and update all lookups/inserts to use the validated type instead of String.

Source: Coding guidelines


80-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Silent fallback to empty JWK coordinates on decode failure, unlike the sibling SDK helper.

point.x().map(base64_url).unwrap_or_default() (and the same for y() on line 91) silently produces an empty-string coordinate if x()/y() ever return None, rather than surfacing an error. The comment above justifies this via the invariant that an uncompressed P-256 encoded point always carries both coordinates for a non-identity key — which is a defensible invariant given a valid signing key — but it means this function can never signal a problem here even though the equivalent trogon-aauth-sdk::signer::public_jwk (which shares near-identical logic) returns a typed error (AgentSignerError::InvalidPublicKey) in the same situation. If the two implementations were unified (see also the comment on signer.rs), this divergence would be eliminated and any future violation of the invariant would surface as an error instead of a malformed/empty-coordinate JWK being published at .well-known.

🤖 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/trogon-jwks-publisher/src/publisher.rs` around lines 80 -
106, The JWK builder in jwk_from_ec_pkcs8_pem currently falls back to empty x/y
coordinates when the encoded point is missing them, which hides a malformed key
condition. Update this path to validate both point.x() and point.y() explicitly
and return a PublisherError (or the shared public-key error used by the sibling
helper) instead of unwrap_or_default, so invalid EC keys fail fast rather than
producing an empty-coordinate JWK. If possible, align this logic with the
equivalent public_jwk implementation to keep both code paths consistent.
rsworkspace/crates/trogon-aauth-sdk/src/signer.rs (1)

171-182: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Duplicate EC→JWK coordinate-extraction logic vs. trogon-jwks-publisher.

public_jwk here duplicates the P-256 point→JWK coordinate logic in trogon-jwks-publisher/src/publisher.rs::jwk_from_ec_pkcs8_pem (that file's own comment acknowledges "mirroring trogon-aauth-sdk's public_jwk helper"). The two implementations have already diverged in error handling: this one returns Err(AgentSignerError::InvalidPublicKey) if x()/y() return None (lines 174-175), while the publisher's version silently falls back to an empty string via unwrap_or_default(). See the companion comment on publisher.rs.

🤖 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/trogon-aauth-sdk/src/signer.rs` around lines 171 - 182,
The P-256 point-to-JWK coordinate extraction is duplicated between public_jwk
and jwk_from_ec_pkcs8_pem, and the two copies have diverged in how missing
coordinates are handled. Update the implementation so both paths share the same
logic or at least the same error behavior, and make the publisher-side helper
match public_jwk by returning an explicit InvalidPublicKey-style error instead
of silently using empty coordinates.
rsworkspace/crates/trogon-aauth-sdk/src/delegation.rs (1)

27-44: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Correct iterative walk; minor repeated allocation.

depth() and contains_agent() each call chain(), reallocating a Vec<String> (with per-node clones) just to count or search. Given delegation chains are expected to be short, this is unlikely to matter in practice.

🤖 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/trogon-aauth-sdk/src/delegation.rs` around lines 27 - 44,
`depth()` and `contains_agent()` are rebuilding the full delegation chain via
`chain()`, which causes avoidable `Vec<String>` allocations and per-node
cloning. Update `depth()` and `contains_agent()` to walk the linked delegation
structure directly using the same iterative traversal logic as `chain()` (or a
shared internal iterator/helper) so counting and membership checks do not
materialize the full chain. Keep the `chain()` method for callers that need the
collected `Vec<String>`, but avoid using it inside `depth()` and
`contains_agent()`.
rsworkspace/crates/trogon-aauth-person/src/store/tests.rs (1)

7-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared claim fixtures to a common test-support module.

agent_claims()/resource_claims() are duplicated verbatim in pending/tests.rs (and similar minting helpers reappear in http/tests.rs). Consider hoisting these into a shared test_support module for the crate so future AgentClaims/ResourceClaims field changes only need a single update.

🤖 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/trogon-aauth-person/src/store/tests.rs` around lines 7 -
35, The claim fixture builders are duplicated across tests, so future
AgentClaims/ResourceClaims changes will be easy to miss. Move agent_claims() and
resource_claims() (and any similar minting helpers used by store tests) into a
shared test_support module for the crate, then have store/tests.rs,
pending/tests.rs, and http/tests.rs import and reuse those helpers instead of
defining their own copies.
rsworkspace/crates/trogon-aauth-person/src/http/mod.rs (2)

239-239: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an explicit mapping for InteractionRequestType here. format!("{:?}", req.type_).to_lowercase() ties the logged value to Debug variant names; a small match or Display impl keeps the log string aligned with the enum and avoids accidental drift on rename.

🤖 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/trogon-aauth-person/src/http/mod.rs` at line 239, The
request type logging in the HTTP module should not depend on Debug variant names
from InteractionRequestType. Update the logic around the type_str assignment to
use an explicit match or a Display implementation for InteractionRequestType so
the logged string is intentionally mapped and stays stable if enum variants are
renamed. Keep the change localized near the req.type_ handling in the
http::mod::interaction request path.

141-151: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Encode the interaction payload explicitly

options is a generic list everywhere else; here it becomes a positional (url, code) payload. Add a dedicated structured field so clients don’t depend on array order.

🤖 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/trogon-aauth-person/src/http/mod.rs` around lines 141 -
151, The PendingPhase::AwaitingResourceInteraction response is encoding the
interaction data as a positional options array, which makes clients depend on
element order. Update the PendingResponse shape used in http/mod.rs to include a
dedicated structured field for the interaction payload, and populate it from the
url and code values instead of packing them into options. Adjust the response
construction in the AwaitingResourceInteraction arm so the payload is explicit
and self-describing.
rsworkspace/crates/trogon-aauth-as/src/error.rs (1)

92-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use PendingRequestId for UnknownPendingRequest
Denied.reason can stay as a string, but UnknownPendingRequest should carry crate::pending::PendingRequestId instead of String so the pending-request identifier stays typed through the error boundary. rsworkspace/crates/trogon-aauth-as/src/error.rs:92-96

🤖 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/trogon-aauth-as/src/error.rs` around lines 92 - 96,
`UnknownPendingRequest` is using an untyped String for the pending-request
identifier, which breaks type safety across the error boundary. Update the
`Error` enum in `error.rs` so `UnknownPendingRequest` carries
`crate::pending::PendingRequestId` instead of `String`, and adjust the
`#[error(...)]` formatting to display that typed id correctly; leave
`Denied.reason` as a String.

Source: Coding guidelines

rsworkspace/crates/trogon-aauth-as/src/test_support.rs (1)

63-155: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Long parameter lists in JWT-minting helpers.

mint_agent_jwt/mint_resource_jwt/mint_auth_jwt_raw each take 7-12 positional args with duplicated header/claims-building logic. Consider a small builder or shared claims-map helper if these grow further, but given this is test-only fixture code, it's not urgent.

🤖 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/trogon-aauth-as/src/test_support.rs` around lines 63 -
155, The JWT minting helpers mint_agent_jwt, mint_resource_jwt, and
mint_auth_jwt_raw all have long positional parameter lists and duplicate
header/claims assembly. Refactor them to reduce argument count and centralize
shared token construction, for example by introducing a small builder or a
shared claims helper that the three functions can reuse, while keeping the
test-fixture behavior unchanged.
rsworkspace/crates/trogon-aauth-person/src/agent/tests.rs (1)

15-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting shared JWK/PEM test fixtures.

The P-256 key generation, PEM export, and JWK-building logic here duplicates near-identical helpers in trogon-aauth-person/src/mint/tests.rs and trogon-aauth-person/tests/person_server_e2e.rs. The sibling trogon-aauth-as crate already has a test_support.rs module for this purpose — a similar crate-local test-support module here would reduce triplicated boilerplate.

🤖 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/trogon-aauth-person/src/agent/tests.rs` around lines 15 -
82, Extract the repeated P-256 key generation, PEM export, JWK/JWK set
construction, and thumbprint helper logic from KeyFixture, key_fixture, and
jkt_of into a crate-local test-support module, then update the tests in
agent/tests.rs and the matching helpers in mint/tests.rs and
person_server_e2e.rs to reuse that shared fixture code instead of duplicating
it.
rsworkspace/crates/trogon-jwks-publisher/src/provider/tests.rs (1)

138-141: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Hardcoded private key PEM triggers secret-scanner noise.

Static analysis flagged this literal as a private key. Since sibling test files in this PR (e.g., agent/tests.rs, mint/tests.rs) already generate P-256 keys dynamically via SigningKey::random(&mut OsRng), consider doing the same here to avoid recurring scanner false-positives and stay consistent with the rest of the PR.

🔑 Proposed fix using dynamic key generation
-fn test_encoding_key() -> EncodingKey {
-    let pem = b"-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\nOF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n-----END PRIVATE KEY-----\n";
-    EncodingKey::from_ec_pem(pem).expect("test signing key")
-}
+fn test_encoding_key() -> EncodingKey {
+    let signing_key = p256::ecdsa::SigningKey::random(&mut rand_core::OsRng);
+    let pem = signing_key
+        .to_pkcs8_pem(pkcs8::LineEnding::LF)
+        .expect("encode pkcs8");
+    EncodingKey::from_ec_pem(pem.as_bytes()).expect("test signing key")
+}
🤖 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/trogon-jwks-publisher/src/provider/tests.rs` around lines
138 - 141, The hardcoded PEM literal in test_encoding_key is being flagged as a
private-key secret, so replace the static test fixture with dynamically
generated P-256 key material like the sibling test helpers in agent/tests.rs and
mint/tests.rs. Update test_encoding_key to create a SigningKey with
SigningKey::random(&mut OsRng), derive the corresponding EncodingKey from it,
and keep the helper returning the same type so the tests remain consistent
without embedding secrets.

Source: Linters/SAST tools

rsworkspace/crates/trogon-aauth-as/Cargo.toml (1)

18-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant duplicate axum dependency.

axum is already declared in [dependencies] with identical spec; the [dev-dependencies] entry adds nothing since main dependencies are already available to tests/dev builds.

🧹 Proposed cleanup
 [dev-dependencies]
-axum = { workspace = true }
 p256 = { version = "=0.13.2", features = ["ecdsa", "pkcs8"] }

Also applies to: 29-29

🤖 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/trogon-aauth-as/Cargo.toml` at line 18, Remove the
redundant axum entry from the dev-dependencies section in the Cargo.toml for
trogon-aauth-as, since axum is already declared in the main dependencies with
the same workspace spec. Keep the dependency only in [dependencies] and apply
the same cleanup anywhere else the duplicate axum dev-dependency appears.
rsworkspace/crates/trogon-jwks-publisher/src/provider.rs (1)

212-220: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

PersonServerUrl doc promises an HTTPS URL but the factory only checks non-empty.

The type is documented as an "HTTPS URL (ps claim)", yet new accepts any non-empty string (e.g. "not a url" or http://...). Per the guideline that a type's factory must guarantee correctness at construction so invalid instances are unrepresentable, consider validating the https:// scheme (mirroring require_https_issuer in the verify crate). The same applies to ProviderIssuer (Lines 117-124), documented as an issuer URL.

As per coding guidelines: "Each type's factory must guarantee correctness at construction—invalid instances should be unrepresentable."

🤖 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/trogon-jwks-publisher/src/provider.rs` around lines 212 -
220, The factories for PersonServerUrl::new and ProviderIssuer::new only reject
empty input, so they can construct invalid URL values despite the docs promising
HTTPS URLs. Update these constructors to validate the parsed string is a proper
https:// URL (not just non-empty), matching the behavior of require_https_issuer
in the verify crate, and return the existing error type when the scheme or URL
format is invalid.

Source: Coding guidelines

rsworkspace/crates/trogon-aauth-person/src/server/tests.rs (1)

384-418: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test doesn't assert mission log accumulation despite its name.

mission_context_flows_into_policy_and_log only checks is_active()/mission_ref().s256; it never asserts on mission.log after the grant, even though PersonServer::apply_decision appends a MissionLogEntry on the grant path. Consider fetching the mission after the grant and asserting the log entry was appended.

🤖 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/trogon-aauth-person/src/server/tests.rs` around lines 384
- 418, The test mission_context_flows_into_policy_and_log does not verify the
log behavior implied by its name; after the grant is applied in
PersonServer::apply_decision, fetch the mission and assert that mission.log
contains the expected MissionLogEntry appended by the grant path. Keep the
existing mission_ref and active-state checks, but add a direct assertion on the
log accumulation after approve_mission/build_server flow so the test covers both
policy and log propagation.
rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs (1)

263-265: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor naming inconsistency: raw string literal vs. ATTR_* constants.

Sibling span fields elsewhere in this function use ATTR_AGENT_SUBJECT, ATTR_ROUTING_OUTCOME, ATTR_CALLER_ID constants; "aauth_agent_id" is a bare literal here.

🤖 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-gateway/src/runtime/dispatch.rs` around lines 263 -
265, The span field name in dispatch::dispatch is inconsistent with the other
ATTR_* constants, since "aauth_agent_id" is a bare string literal while nearby
fields use constants like ATTR_AGENT_SUBJECT, ATTR_ROUTING_OUTCOME, and
ATTR_CALLER_ID. Replace the literal with a matching constant-style identifier
(or introduce a dedicated constant alongside the others) and use it in the
tracing::Span::current().record call so all span attribute keys are defined
consistently in one place.
rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs (1)

181-190: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Body is serialized twice for signing vs. sending.

serde_json::to_vec(request) computes signing bytes separately from .json(request), which reqwest serializes again internally. Currently harmless since SignatureKeyOnlyHttpSigner ignores the body argument, but it's wasted work and a latent correctness trap for a future signer that actually signs over body — any serializer non-determinism between the two calls would desync the signature from the wire bytes.

Also applies to: 267-271

🤖 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/trogon-aauth-sdk/src/exchange/client.rs` around lines 181
- 190, In the exchange client request path, the request body is serialized
twice: once via serde_json::to_vec(request) for signing and again via
.json(request) for sending, which can drift and wastes work. Update the
request-building flow in client.rs around the sign(builder, &body) call so a
single serialized body is produced and reused for both the signer and the HTTP
request. Apply the same fix to the second duplicated exchange path noted in the
comment, using the same exchange request-building symbols to keep signing bytes
and wire bytes identical.
rsworkspace/crates/trogon-aauth-as/src/pending.rs (1)

45-78: 🩺 Stability & Availability | 🔵 Trivial

Unbounded pending store — abandoned requirement=claims entries never expire.

insert adds an entry that is only removed by a successful take. A PS that receives a 202 but never POSTs the claims leaves the entry resident forever, so a stream of claims-required requests grows entries without bound (memory pressure / DoS surface). This aligns with the documented single-node follow-up, but consider a TTL/eviction sweep or capacity bound before enabling in production.

🤖 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/trogon-aauth-as/src/pending.rs` around lines 45 - 78, The
PendingRequestStore in pending.rs can grow without bound because PendingRequest
entries inserted via insert are only removed by take, so abandoned
claims-required requests never expire. Add an eviction strategy to
PendingRequestStore, such as a TTL with periodic cleanup or a bounded
capacity/least-recently-used policy, and make sure new entries are aged out
automatically even when ClaimsSubmission never arrives. Use the existing
PendingRequestStore, insert, take, and entries symbols to implement the fix
without changing the one-shot semantics of take.
rsworkspace/crates/trogon-aauth-person/src/mission/tests.rs (1)

66-72: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test doesn't actually verify the "one-way" claim in its name.

Only a single complete() call is exercised; nothing asserts that the transition is irreversible or idempotent (e.g. a second complete() call, or that append_log/state mutation after completion is rejected if that's the intended invariant).

✅ Suggested strengthening
 fn complete_transitions_to_terminated_and_is_one_way() {
     let bytes = serde_json::to_vec(&blob()).unwrap();
     let mut mission = Mission::approve(bytes, blob());
     mission.complete();
     assert!(!mission.is_active());
     assert_eq!(mission.status, MissionStatus::Terminated);
+    // Calling complete() again (or any further activation) must not un-terminate the mission.
+    mission.complete();
+    assert_eq!(mission.status, MissionStatus::Terminated);
 }
🤖 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/trogon-aauth-person/src/mission/tests.rs` around lines 66
- 72, The test name claims the transition is one-way, but it only checks a
single call to Mission::complete. Strengthen
complete_transitions_to_terminated_and_is_one_way by asserting the
post-completion behavior is irreversible, such as calling Mission::complete a
second time and verifying the status remains MissionStatus::Terminated and the
mission stays inactive. If Mission exposes mutation helpers like append_log or
similar state-changing methods, also verify they are rejected or have no effect
after completion.
🤖 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/trogon-aauth-as/src/http.rs`:
- Around line 70-85: The resume_endpoint handler currently accepts a
ClaimsSubmission without verifying the caller’s authenticated PS identity.
Update resume_endpoint to also extract Extension<PsIdentity>, then compare that
identity against the TrustedIssuer associated with the PendingRequest for the
PendingRequestId before calling server.resume_with_claims. If the PS does not
match, return an error response instead of proceeding, and keep the existing
outcome_response/error_response flow for the authorized path.

In `@rsworkspace/crates/trogon-aauth-as/src/policy.rs`:
- Around line 60-70: `Decision::Deny` currently stores denial cause as a raw
`String`, but the review expects a typed error value. Update the `Decision` enum
in `policy.rs` to replace `reason: String` with a typed `DenialReason` (prefer
an enum or newtype consistent with `GrantedScope` and `RequiredClaims`), then
adjust any constructors, matches, and token-endpoint error conversion code that
uses `Decision::Deny` so callers can inspect the denial cause without parsing
text.

In `@rsworkspace/crates/trogon-aauth-as/src/server.rs`:
- Around line 277-284: The pending ID generator in fresh_pending_id is
predictable because it derives the value from SystemTime::now().as_nanos(), so
replace it with a CSPRNG-backed identifier such as UUIDv4 or a 128-bit random
hex string. Update the fresh_pending_id helper in server.rs to generate an
unguessable value, and keep the returned string in the same format expected by
the pending-request store and Location URL usage.

In `@rsworkspace/crates/trogon-aauth-person/src/agent.rs`:
- Around line 54-60: The subagent check in agent verification is currently
swallowing parse/decode failures by using
parent_agent_of(agent_token).unwrap_or(None), which can let an invalid token
pass as a primary agent token. Update the logic around verify_agent and
parent_agent_of to fail closed: propagate the parent lookup error instead of
treating it as None, and map it through RequestVerificationError. Add a
RequestVerificationError variant that wraps ParentAgentError, and use it so any
token that cannot be parsed is rejected rather than accepted.

In `@rsworkspace/crates/trogon-aauth-person/src/error.rs`:
- Around line 79-97: The pending-request and mission error variants are using
bare String identifiers instead of the existing domain types. Update
PendingRequestError (and MissionNotFound if it shares the same pattern) to carry
MissionId or PendingId as appropriate, and adjust the Display/error annotations
plus any constructors/conversions in the surrounding error types to match. Use
the existing MissionId and PendingId re-exports from the crate so the typed
identifiers flow through the API consistently.
- Around line 118-124: Map
PersonServerError::Interaction(InteractionRelayError::UserUnreachable)
explicitly in token_endpoint_code() to the same UserUnreachable token endpoint
result as PersonServerError::UserUnreachable instead of falling through to
ServerError; then ensure http_status() continues to reflect that mapping through
token_endpoint_code(). Use the existing PersonServerError,
InteractionRelayError::UserUnreachable, token_endpoint_code(), and http_status()
symbols to locate the change.

In `@rsworkspace/crates/trogon-aauth-person/src/error/tests.rs`:
- Around line 1-64: Add test coverage in the existing PersonServerError error
tests for the InteractionRelayError::UserUnreachable case. In tests.rs, create a
case using
PersonServerError::Interaction(InteractionRelayError::UserUnreachable) and
assert that token_endpoint_code() resolves to
TokenEndpointError::UserUnreachable and http_status() resolves to 403, matching
the top-level UserUnreachable behavior. Use the existing PersonServerError,
InteractionRelayError, token_endpoint_code(), and http_status() symbols to
locate the mapping gap.

In `@rsworkspace/crates/trogon-aauth-person/src/http/mod.rs`:
- Around line 75-79: The HTTP error builder in error_response is leaking
internal verification details by passing err.to_string() into
ErrorResponse::with_detail. Change error_response so PersonServerError still
maps to the same status and wire_code, but the response detail is either a
generic client-safe auth message or omitted entirely for these failures. Keep
the fix localized to error_response and preserve the existing wire_code-based
error identification.

In `@rsworkspace/crates/trogon-aauth-person/src/mission.rs`:
- Around line 29-42: The Mission record is persisting a wire/input type
directly, since Mission currently stores MissionBlob and
PersonStateStore::insert_mission carries it through unchanged. Update the
mission storage path to convert MissionBlob into a validated domain type at the
boundary, and change Mission to hold only the domain representation needed for
runtime/storage instead of the raw wire type. Keep MissionBlob/mission log wire
bodies only at the deserialization edge, and ensure the persisted state uses
validated domain data only.
- Around line 15-27: MissionId currently exposes its inner String publicly,
which allows bypassing the invariant enforced by MissionId::from_blob_bytes.
Make the MissionId field private in the MissionId type, add a read-only accessor
or Deref if needed, and introduce an explicit constructor such as from_verified
for cases like server.rs that are already trusted. Ensure all construction paths
outside MissionId::from_blob_bytes go through these controlled APIs so invalid
MissionId values cannot be created directly.

In `@rsworkspace/crates/trogon-aauth-person/src/pending.rs`:
- Around line 21-41: PendingId generation in PendingId::generate uses
uuid_like(), which is predictable because it combines a process-global counter
and timestamp; replace it with a CSPRNG-backed unguessable ID. Update
uuid_like() to draw at least 128 bits of randomness from a secure source such as
rand/getrandom and encode it into a compact string form, while keeping
PendingId::generate as the single call site that constructs the ID.

In `@rsworkspace/crates/trogon-aauth-person/src/server.rs`:
- Around line 113-485: Store failures are being collapsed into
`PendingRequestError::NotFound`, which makes write and infrastructure errors
look like missing resources. Update `PersonServerError` and the error mappings
in `server.rs` so lookup methods still use `NotFound`, but `insert_pending`,
`update_pending`, `insert_mission`, `update_mission`, and similar write paths
return a dedicated store/error variant instead. Apply this consistently in
`persist`, `apply_decision`, `approve_mission`, `complete_mission`,
`append_mission_log`, `poll_pending`, `load_mission_context`, and the
clarification flow so callers can distinguish real absence from backend
failures.
- Around line 224-248: The interaction URL in `server.rs` is hardcoded to the
reserved `ps.invalid` domain inside the `PolicyDecision::NeedsInteraction`
handling, which breaks the `InteractionNotice` link in real deployments. Update
the URL construction to use the server’s actual issuer/base from `self.iss` (or
the appropriate existing issuer field on `PersonServer`) when building the
`InteractionNotice`, so the `InteractionNotice` URL resolves correctly while
keeping the same pending-id path and interaction flow.
- Around line 113-160: The pending correlation flow in `PersonServer::...` is
race-prone because `find_pending_by_correlation` and the later pending creation
path are separate operations, so concurrent requests can create duplicate
records. Update the lookup/create logic around
`PendingRequest::correlation_key_for`, `find_pending_by_correlation`, and the
pending insertion path to use a single atomic get-or-create mechanism, or
enforce a unique constraint/transaction in the store, so repeated requests
always reuse the same pending entry.
- Around line 406-421: The clarification round-trip in respond_to_clarification
is dropping the upstream delegation chain because it rebuilds VerifiedRequest
with upstream set to None. Preserve the upstream auth state from the pending
request when reconstructing VerifiedRequest, and make sure apply_decision still
receives that chain so the minted token continues to nest act correctly for
requests that arrived with an upstream_token.

In `@rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs`:
- Around line 292-320: The polling loop in handle_response can spin indefinitely
when Retry-After is 0, so add a minimum sleep floor and a hard cap on
retries/overall polling duration. Update the handle_response flow to apply
core::DEFAULT_POLL_INTERVAL_SECS (or another shared minimum) whenever after_secs
is too small, and track poll iterations in ExchangeState or a local counter so
ExchangeAction::PollAfter cannot loop forever. Keep the fix localized to
handle_response, step, and the ExchangeState/outcome path so repeated
Pending/SlowDown responses are throttled and eventually fail cleanly.

In `@rsworkspace/crates/trogon-aauth-verify/src/jwks_http.rs`:
- Around line 255-263: The JWKS fetch path in the response body parsing logic
currently buffers the entire payload via response.bytes().await before checking
max_response_bytes, so the cap is enforced too late. Update the body handling in
jwks_http.rs to stream the response in chunks, accumulating into a buffer only
while tracking size and aborting as soon as the limit is exceeded; keep the
existing JSON parsing and error mapping in the JWK set parsing flow, especially
around the response.bytes()/from_slice logic.
- Around line 220-227: The issuer validation in require_https_issuer only checks
for an https:// prefix, so untrusted issuers can still point at arbitrary HTTPS
hosts. Tighten the validation in jwks_http.rs by rejecting private, loopback,
and link-local destinations (or otherwise enforcing a trusted allowlist) before
returning the normalized issuer, and ensure HttpJwksResolver::new in
a2a-gateway/src/runtime/aauth_env.rs only receives issuers that have passed this
trust check.

In `@rsworkspace/crates/trogon-identity-types/src/aauth/login.rs`:
- Around line 101-118: The `urldecode` helper in `login.rs` slices `&str` with
`&s[i + 1..i + 3]`, which can panic on malformed UTF-8 input and is reachable
through public `parse_query_string`. Update `urldecode` to read the two hex
characters directly from the `bytes` buffer (`bytes[i + 1]` and `bytes[i + 2]`)
before decoding with `u8::from_str_radix`, so decoding never depends on
potentially invalid string slicing.

---

Minor comments:
In `@rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs`:
- Around line 234-239: The JWKS TTL parsing in well_known_resolver_from_env
currently accepts negative values from optional_i64, which causes
CachedJwksResolver to effectively disable caching; validate or clamp
ENV_AAUTH_JWKS_TTL_SECS to a non-negative value before passing it into
CachedJwksResolver::new(...).with_ttl_secs(...), and return an AAuthEnvError if
the env value is negative so the bad configuration is rejected early.

In `@rsworkspace/crates/trogon-aauth-as/src/subagent.rs`:
- Around line 36-45: The shape validation in parent_agent_of only consumes two
split segments, so it can accept a token with no signature segment even though
BadShape implies three dot-separated parts. Update the parsing in
parent_agent_of to explicitly verify that the JWT has exactly three segments
before decoding the payload, and keep the existing ParentAgentError::BadShape
path for any malformed input.

In `@rsworkspace/crates/trogon-aauth-sdk/src/subagent.rs`:
- Around line 54-56: Decode failures in parent_agent_of are being collapsed into
None, which hides malformed token errors and turns them into NotASubAgentToken.
Update parent_agent_of and the decode_payload flow in subagent.rs to preserve
and propagate the underlying decode error instead of discarding it, and make
build_subagent_token_request return the decode failure directly for
subagent_agent_jwt so malformed input surfaces as MalformedAgentToken. Keep the
error context attached in the typed error path rather than converting it to a
string or Option.

In `@rsworkspace/crates/trogon-aauth-verify/src/mission.rs`:
- Around line 13-16: The module docs contain a broken intra-doc link because
they refer to MissionClaim, but this crate actually uses MissionRef in this
context. Update the doc comment near extract_mission_claim and AuthClaims to
point the link at MissionRef so rustdoc resolves it correctly and the
documentation stays consistent with the types used here.

---

Nitpick comments:
In `@rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs`:
- Around line 263-265: The span field name in dispatch::dispatch is inconsistent
with the other ATTR_* constants, since "aauth_agent_id" is a bare string literal
while nearby fields use constants like ATTR_AGENT_SUBJECT, ATTR_ROUTING_OUTCOME,
and ATTR_CALLER_ID. Replace the literal with a matching constant-style
identifier (or introduce a dedicated constant alongside the others) and use it
in the tracing::Span::current().record call so all span attribute keys are
defined consistently in one place.

In `@rsworkspace/crates/trogon-aauth-as/Cargo.toml`:
- Line 18: Remove the redundant axum entry from the dev-dependencies section in
the Cargo.toml for trogon-aauth-as, since axum is already declared in the main
dependencies with the same workspace spec. Keep the dependency only in
[dependencies] and apply the same cleanup anywhere else the duplicate axum
dev-dependency appears.

In `@rsworkspace/crates/trogon-aauth-as/src/error.rs`:
- Around line 92-96: `UnknownPendingRequest` is using an untyped String for the
pending-request identifier, which breaks type safety across the error boundary.
Update the `Error` enum in `error.rs` so `UnknownPendingRequest` carries
`crate::pending::PendingRequestId` instead of `String`, and adjust the
`#[error(...)]` formatting to display that typed id correctly; leave
`Denied.reason` as a String.

In `@rsworkspace/crates/trogon-aauth-as/src/pending.rs`:
- Around line 45-78: The PendingRequestStore in pending.rs can grow without
bound because PendingRequest entries inserted via insert are only removed by
take, so abandoned claims-required requests never expire. Add an eviction
strategy to PendingRequestStore, such as a TTL with periodic cleanup or a
bounded capacity/least-recently-used policy, and make sure new entries are aged
out automatically even when ClaimsSubmission never arrives. Use the existing
PendingRequestStore, insert, take, and entries symbols to implement the fix
without changing the one-shot semantics of take.

In `@rsworkspace/crates/trogon-aauth-as/src/test_support.rs`:
- Around line 63-155: The JWT minting helpers mint_agent_jwt, mint_resource_jwt,
and mint_auth_jwt_raw all have long positional parameter lists and duplicate
header/claims assembly. Refactor them to reduce argument count and centralize
shared token construction, for example by introducing a small builder or a
shared claims helper that the three functions can reuse, while keeping the
test-fixture behavior unchanged.

In `@rsworkspace/crates/trogon-aauth-person/src/agent/tests.rs`:
- Around line 15-82: Extract the repeated P-256 key generation, PEM export,
JWK/JWK set construction, and thumbprint helper logic from KeyFixture,
key_fixture, and jkt_of into a crate-local test-support module, then update the
tests in agent/tests.rs and the matching helpers in mint/tests.rs and
person_server_e2e.rs to reuse that shared fixture code instead of duplicating
it.

In `@rsworkspace/crates/trogon-aauth-person/src/http/mod.rs`:
- Line 239: The request type logging in the HTTP module should not depend on
Debug variant names from InteractionRequestType. Update the logic around the
type_str assignment to use an explicit match or a Display implementation for
InteractionRequestType so the logged string is intentionally mapped and stays
stable if enum variants are renamed. Keep the change localized near the
req.type_ handling in the http::mod::interaction request path.
- Around line 141-151: The PendingPhase::AwaitingResourceInteraction response is
encoding the interaction data as a positional options array, which makes clients
depend on element order. Update the PendingResponse shape used in http/mod.rs to
include a dedicated structured field for the interaction payload, and populate
it from the url and code values instead of packing them into options. Adjust the
response construction in the AwaitingResourceInteraction arm so the payload is
explicit and self-describing.

In `@rsworkspace/crates/trogon-aauth-person/src/mission/tests.rs`:
- Around line 66-72: The test name claims the transition is one-way, but it only
checks a single call to Mission::complete. Strengthen
complete_transitions_to_terminated_and_is_one_way by asserting the
post-completion behavior is irreversible, such as calling Mission::complete a
second time and verifying the status remains MissionStatus::Terminated and the
mission stays inactive. If Mission exposes mutation helpers like append_log or
similar state-changing methods, also verify they are rejected or have no effect
after completion.

In `@rsworkspace/crates/trogon-aauth-person/src/server/tests.rs`:
- Around line 384-418: The test mission_context_flows_into_policy_and_log does
not verify the log behavior implied by its name; after the grant is applied in
PersonServer::apply_decision, fetch the mission and assert that mission.log
contains the expected MissionLogEntry appended by the grant path. Keep the
existing mission_ref and active-state checks, but add a direct assertion on the
log accumulation after approve_mission/build_server flow so the test covers both
policy and log propagation.

In `@rsworkspace/crates/trogon-aauth-person/src/store/tests.rs`:
- Around line 7-35: The claim fixture builders are duplicated across tests, so
future AgentClaims/ResourceClaims changes will be easy to miss. Move
agent_claims() and resource_claims() (and any similar minting helpers used by
store tests) into a shared test_support module for the crate, then have
store/tests.rs, pending/tests.rs, and http/tests.rs import and reuse those
helpers instead of defining their own copies.

In `@rsworkspace/crates/trogon-aauth-sdk/Cargo.toml`:
- Around line 26-34: Remove the redundant test-only re-declaration of
trogon-aauth-verify in Cargo.toml for trogon-aauth-sdk, since it is already
available through the existing [dependencies] entry with workspace = true. Keep
the dependency only once in the manifest and leave the other dev-dependencies
unchanged; use the trogon-aauth-verify and [dev-dependencies] entries to locate
the duplicate.

In `@rsworkspace/crates/trogon-aauth-sdk/src/delegation.rs`:
- Around line 27-44: `depth()` and `contains_agent()` are rebuilding the full
delegation chain via `chain()`, which causes avoidable `Vec<String>` allocations
and per-node cloning. Update `depth()` and `contains_agent()` to walk the linked
delegation structure directly using the same iterative traversal logic as
`chain()` (or a shared internal iterator/helper) so counting and membership
checks do not materialize the full chain. Keep the `chain()` method for callers
that need the collected `Vec<String>`, but avoid using it inside `depth()` and
`contains_agent()`.

In `@rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs`:
- Around line 181-190: In the exchange client request path, the request body is
serialized twice: once via serde_json::to_vec(request) for signing and again via
.json(request) for sending, which can drift and wastes work. Update the
request-building flow in client.rs around the sign(builder, &body) call so a
single serialized body is produced and reused for both the signer and the HTTP
request. Apply the same fix to the second duplicated exchange path noted in the
comment, using the same exchange request-building symbols to keep signing bytes
and wire bytes identical.

In `@rsworkspace/crates/trogon-aauth-sdk/src/signer.rs`:
- Around line 171-182: The P-256 point-to-JWK coordinate extraction is
duplicated between public_jwk and jwk_from_ec_pkcs8_pem, and the two copies have
diverged in how missing coordinates are handled. Update the implementation so
both paths share the same logic or at least the same error behavior, and make
the publisher-side helper match public_jwk by returning an explicit
InvalidPublicKey-style error instead of silently using empty coordinates.

In `@rsworkspace/crates/trogon-identity-types/src/aauth/mission.rs`:
- Around line 106-129: MissionHeader::parse is duplicating header parsing logic
instead of using the shared split_header helper used by Requirement::parse, and
it currently aborts on any malformed segment rather than handling invalid parts
consistently. Update MissionHeader::parse in mission.rs to reuse split_header
(or factor both parsers onto a common helper) so parsing behavior matches the
existing tolerant approach, while still extracting approver and s256 from the
parsed segments.

In `@rsworkspace/crates/trogon-jwks-publisher/src/provider.rs`:
- Around line 212-220: The factories for PersonServerUrl::new and
ProviderIssuer::new only reject empty input, so they can construct invalid URL
values despite the docs promising HTTPS URLs. Update these constructors to
validate the parsed string is a proper https:// URL (not just non-empty),
matching the behavior of require_https_issuer in the verify crate, and return
the existing error type when the scheme or URL format is invalid.

In `@rsworkspace/crates/trogon-jwks-publisher/src/provider/tests.rs`:
- Around line 138-141: The hardcoded PEM literal in test_encoding_key is being
flagged as a private-key secret, so replace the static test fixture with
dynamically generated P-256 key material like the sibling test helpers in
agent/tests.rs and mint/tests.rs. Update test_encoding_key to create a
SigningKey with SigningKey::random(&mut OsRng), derive the corresponding
EncodingKey from it, and keep the helper returning the same type so the tests
remain consistent without embedding secrets.

In `@rsworkspace/crates/trogon-jwks-publisher/src/publisher.rs`:
- Around line 116-168: The builder and config currently store dwk names as raw
String keys, so validity is only checked at insertion time in
JwksPublisherConfigBuilder::with_jwk_set. Introduce a domain-specific
DwkFilename newtype/enum with a fallible constructor and use it in
JwksPublisherConfigBuilder::entries, JwksPublisherConfig::entries, and the
serve_dwk path extractor so only valid registered filenames can exist by type.
Keep the existing uniqueness and known-dwk checks at the conversion boundary,
and update all lookups/inserts to use the validated type instead of String.
- Around line 80-106: The JWK builder in jwk_from_ec_pkcs8_pem currently falls
back to empty x/y coordinates when the encoded point is missing them, which
hides a malformed key condition. Update this path to validate both point.x() and
point.y() explicitly and return a PublisherError (or the shared public-key error
used by the sibling helper) instead of unwrap_or_default, so invalid EC keys
fail fast rather than producing an empty-coordinate JWK. If possible, align this
logic with the equivalent public_jwk implementation to keep both code paths
consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Comment thread rsworkspace/crates/trogon-aauth-as/src/http.rs
Comment thread rsworkspace/crates/trogon-aauth-as/src/policy.rs
Comment thread rsworkspace/crates/trogon-aauth-as/src/server.rs
Comment thread rsworkspace/crates/trogon-aauth-person/src/agent.rs
Comment thread rsworkspace/crates/trogon-aauth-person/src/error.rs
Comment thread rsworkspace/crates/trogon-aauth-person/src/server.rs
Comment thread rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs
Comment thread rsworkspace/crates/trogon-aauth-verify/src/jwks_http.rs
Comment thread rsworkspace/crates/trogon-aauth-verify/src/jwks_http.rs Outdated
Comment thread rsworkspace/crates/trogon-identity-types/src/aauth/login.rs
Comment thread rsworkspace/crates/trogon-aauth-person/src/server.rs Outdated
Comment thread rsworkspace/crates/trogon-aauth-person/src/server.rs Outdated
Comment thread rsworkspace/crates/trogon-aauth-person/src/server.rs Outdated
yordis added 8 commits July 7, 2026 06:45
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…g store and policy failures as not-found

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…ending ids unguessable

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…map relay user_unreachable

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
… details and validate mission blobs at the boundary

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…n get-or-create atomic

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…delegation context across resumes, and throttle sdk polling

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…ap, and decode login escapes without panicking

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs Outdated
Comment thread rsworkspace/crates/trogon-aauth-as/src/verify.rs

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rsworkspace/crates/trogon-aauth-as/src/server.rs (1)

104-108: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Don't swallow an invalid collapsed-mode ps_iss.

If PsIssuer::new(ps_iss.clone()) fails here, the server still starts and only rejects requests later as untrusted. This should fail during construction instead—ideally by storing a validated issuer value object in FederationMode::Collapsed or by making AccessServer::new(...) return a typed init error. Based on learnings from the PR objectives, this regresses the "misconfigured auth layer fails to start" goal. As per coding guidelines: "Prefer domain-specific value objects over primitives" and "Each type's factory must guarantee correctness at construction—invalid instances should be unrepresentable."

🤖 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/trogon-aauth-as/src/server.rs` around lines 104 - 108, The
collapsed-mode `ps_iss` validation is being ignored in `AccessServer::new`,
which lets startup succeed with an invalid issuer and fails later at request
time. Make construction fail fast by validating `ps_iss` before building the
server or, better, by moving the checked issuer into `FederationMode::Collapsed`
as a validated value object so invalid state is unrepresentable. If validation
still happens in `AccessServer::new`, return a typed init error instead of
silently skipping `PsIssuer::new` failures and only calling `trust.trust` when
the issuer is guaranteed valid.

Source: Coding guidelines

🧹 Nitpick comments (1)
rsworkspace/crates/trogon-aauth-as/src/policy.rs (1)

65-69: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make DenialReason reject blank values.

DenialReason::new(...) currently accepts empty/whitespace strings even though this value is emitted verbatim in the denied response detail, so the value object still doesn't guarantee a valid domain instance. Make the constructor validate and return a typed error, or switch to a closed enum if the denial set is finite. As per coding guidelines: "Each type's factory must guarantee correctness at construction—invalid instances should be unrepresentable."

🤖 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/trogon-aauth-as/src/policy.rs` around lines 65 - 69,
DenialReason::new currently allows empty or whitespace-only strings, so the
value object can be constructed in an invalid state. Update the DenialReason
constructor in the DenialReason impl to validate the input, reject blank values,
and return a typed error instead of always producing Self. If the set of reasons
is meant to be finite, consider replacing the free-form string wrapper with a
closed enum so invalid denial reasons are unrepresentable.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@rsworkspace/crates/trogon-aauth-as/src/server.rs`:
- Around line 104-108: The collapsed-mode `ps_iss` validation is being ignored
in `AccessServer::new`, which lets startup succeed with an invalid issuer and
fails later at request time. Make construction fail fast by validating `ps_iss`
before building the server or, better, by moving the checked issuer into
`FederationMode::Collapsed` as a validated value object so invalid state is
unrepresentable. If validation still happens in `AccessServer::new`, return a
typed init error instead of silently skipping `PsIssuer::new` failures and only
calling `trust.trust` when the issuer is guaranteed valid.

---

Nitpick comments:
In `@rsworkspace/crates/trogon-aauth-as/src/policy.rs`:
- Around line 65-69: DenialReason::new currently allows empty or whitespace-only
strings, so the value object can be constructed in an invalid state. Update the
DenialReason constructor in the DenialReason impl to validate the input, reject
blank values, and return a typed error instead of always producing Self. If the
set of reasons is meant to be finite, consider replacing the free-form string
wrapper with a closed enum so invalid denial reasons are unrepresentable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7730be2e-e39d-43bf-8e37-02371af24dde

📥 Commits

Reviewing files that changed from the base of the PR and between 999a5e3 and 43fa305.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (32)
  • rsworkspace/crates/a2a-gateway/src/aauth.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env/tests.rs
  • rsworkspace/crates/a2a-gateway/tests/aauth_roundtrip.rs
  • rsworkspace/crates/a2a-gateway/tests/aauth_three_party_e2e.rs
  • rsworkspace/crates/trogon-aauth-as/Cargo.toml
  • rsworkspace/crates/trogon-aauth-as/src/http.rs
  • rsworkspace/crates/trogon-aauth-as/src/pending.rs
  • rsworkspace/crates/trogon-aauth-as/src/policy.rs
  • rsworkspace/crates/trogon-aauth-as/src/policy/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/server.rs
  • rsworkspace/crates/trogon-aauth-as/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-person/Cargo.toml
  • rsworkspace/crates/trogon-aauth-person/src/agent.rs
  • rsworkspace/crates/trogon-aauth-person/src/error.rs
  • rsworkspace/crates/trogon-aauth-person/src/error/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/http/mod.rs
  • rsworkspace/crates/trogon-aauth-person/src/lib.rs
  • rsworkspace/crates/trogon-aauth-person/src/mission.rs
  • rsworkspace/crates/trogon-aauth-person/src/mission/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/pending.rs
  • rsworkspace/crates/trogon-aauth-person/src/pending/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/server.rs
  • rsworkspace/crates/trogon-aauth-person/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/store.rs
  • rsworkspace/crates/trogon-aauth-person/src/store/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/Cargo.toml
  • rsworkspace/crates/trogon-aauth-verify/src/jwks_http.rs
  • rsworkspace/crates/trogon-aauth-verify/src/jwks_http/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/login.rs
🚧 Files skipped from review as they are similar to previous changes (20)
  • rsworkspace/crates/trogon-aauth-as/src/policy/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/Cargo.toml
  • rsworkspace/crates/trogon-aauth-person/src/mission/tests.rs
  • rsworkspace/crates/trogon-aauth-person/Cargo.toml
  • rsworkspace/crates/trogon-aauth-person/src/lib.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/login.rs
  • rsworkspace/crates/trogon-aauth-as/Cargo.toml
  • rsworkspace/crates/trogon-aauth-person/src/pending/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/agent.rs
  • rsworkspace/crates/trogon-aauth-as/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/pending.rs
  • rsworkspace/crates/trogon-aauth-as/src/http.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/error.rs
  • rsworkspace/crates/a2a-gateway/tests/aauth_three_party_e2e.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs
  • rsworkspace/crates/trogon-aauth-person/src/http/mod.rs
  • rsworkspace/crates/a2a-gateway/src/aauth.rs
  • rsworkspace/crates/trogon-aauth-person/src/server.rs

yordis added 2 commits July 7, 2026 16:09
…d resource tokens to the agent identifier

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…e workspace lint

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
yordis added 3 commits July 7, 2026 16:27
…s for the coverage gate

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

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

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
Comment thread rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs
Comment thread rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs Outdated
Comment thread rsworkspace/crates/trogon-aauth-as/src/verify.rs
… token headers, and log deny encode failures

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 1 potential issue.

There are 5 total unresolved issues (including 4 from previous reviews).

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 25f2e45. Configure here.

Comment thread rsworkspace/crates/a2a-gateway/src/aauth.rs
…metry key constant

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

@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: 1

🧹 Nitpick comments (2)
rsworkspace/crates/trogon-aauth-sdk/src/exchange/challenge/tests.rs (1)

14-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer a runtime-generated key over a hardcoded test PEM.

Static analysis flags this as a private key. It's test-only fixture material so not a real leak, but other test fixtures in this PR (e.g. SigningKey::random(&mut OsRng) in trogon-aauth-person/src/server/tests.rs) generate keys at runtime instead of hardcoding PEM bytes, avoiding secret-scanner noise and one less magic constant to maintain.

♻️ Suggested approach
-const P256_PEM: &[u8] = b"-----BEGIN PRIVATE KEY-----\n...==\n-----END PRIVATE KEY-----\n";
-
-fn p256_jwk_for_test() -> jsonwebtoken::jwk::Jwk {
-    serde_json::from_value(serde_json::json!({
-        "kty": "EC", "crv": "P-256", "kid": "k1", "alg": "ES256", "use": "sig",
-        "x": "EVs_o5-uQbTjL3chynL4wXgUg2R9q9UU8I5mEovUf84",
-        "y": "kGe5DgSIycKp8w9aJmoHhB1sB3QTugfnRWm5nU_TzsY"
-    }))
-    .unwrap()
-}
-
-fn signed_resource_token(claims: &serde_json::Value) -> String {
-    let signing = jsonwebtoken::EncodingKey::from_ec_pem(P256_PEM).expect("signing key");
+fn signed_resource_token(claims: &serde_json::Value, signing_key: &p256::ecdsa::SigningKey) -> String {
+    let pem = signing_key.to_pkcs8_pem(pkcs8::LineEnding::LF).unwrap();
+    let signing = jsonwebtoken::EncodingKey::from_ec_pem(pem.as_bytes()).expect("signing key");
     let mut header = jsonwebtoken::Header::new(Algorithm::ES256);
     header.typ = Some(TYP_RESOURCE.into());
     header.kid = Some("k1".into());
     jsonwebtoken::encode(&header, claims, &signing).expect("encode")
 }

(derive the matching JWK's x/y from the generated verifying key, as done elsewhere in this codebase via EncodedPoint).

🤖 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/trogon-aauth-sdk/src/exchange/challenge/tests.rs` at line
14, Replace the hardcoded P256_PEM fixture in the challenge tests with a key
generated at runtime, similar to the SigningKey::random(&mut OsRng) pattern used
in trogon-aauth-person/src/server/tests.rs. Update the relevant challenge test
setup to derive the corresponding JWK values from the generated verifying key
using the existing EncodedPoint-based approach, so the test still exercises the
same behavior without embedding private-key PEM bytes.

Source: Linters/SAST tools

rsworkspace/crates/trogon-aauth-as/src/http/tests.rs (1)

25-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate ScopeSwitchedPolicy within the same crate.

An equivalent ScopeSwitchedPolicy/decide impl already exists in trogon-aauth-as/src/policy/tests.rs (same crate, per graph context). Since crate::test_support already provides shared test fixtures used by this file, consider moving ScopeSwitchedPolicy there so both test modules share one definition instead of two copies that can drift.

🤖 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/trogon-aauth-as/src/http/tests.rs` around lines 25 - 52,
There is a duplicated test-only ScopeSwitchedPolicy implementation in this
module that already exists elsewhere in the same crate, so consolidate it into
the shared crate::test_support fixtures instead of keeping two copies. Move the
OrganizationPolicy implementation for ScopeSwitchedPolicy into the shared test
support area and update the tests in http/tests.rs and the existing policy tests
to import and use that single definition. Keep the decide and decide_with_claims
behavior unchanged while removing the duplicate local struct/impl.
🤖 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/trogon-aauth-sdk/src/verify_response/tests.rs`:
- Around line 244-264: The test name is misleading because the scenario in
with_jwks_runs_claims_checks_after_signature_and_surfaces_audience_mismatch
actually varies own_agent_id and asserts VerifyResponseError::AgentMismatch, not
an audience failure. Rename the test to reflect the real condition under test
and keep the assertion aligned with the current behavior in
verify_auth_token_response_with_jwks so the name matches the error variant being
checked.

---

Nitpick comments:
In `@rsworkspace/crates/trogon-aauth-as/src/http/tests.rs`:
- Around line 25-52: There is a duplicated test-only ScopeSwitchedPolicy
implementation in this module that already exists elsewhere in the same crate,
so consolidate it into the shared crate::test_support fixtures instead of
keeping two copies. Move the OrganizationPolicy implementation for
ScopeSwitchedPolicy into the shared test support area and update the tests in
http/tests.rs and the existing policy tests to import and use that single
definition. Keep the decide and decide_with_claims behavior unchanged while
removing the duplicate local struct/impl.

In `@rsworkspace/crates/trogon-aauth-sdk/src/exchange/challenge/tests.rs`:
- Line 14: Replace the hardcoded P256_PEM fixture in the challenge tests with a
key generated at runtime, similar to the SigningKey::random(&mut OsRng) pattern
used in trogon-aauth-person/src/server/tests.rs. Update the relevant challenge
test setup to derive the corresponding JWK values from the generated verifying
key using the existing EncodedPoint-based approach, so the test still exercises
the same behavior without embedding private-key PEM bytes.
🪄 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: fa5e11c7-cbf4-4f89-b0c0-a4d84d66140d

📥 Commits

Reviewing files that changed from the base of the PR and between 43fa305 and fd3d705.

📒 Files selected for processing (35)
  • rsworkspace/crates/a2a-gateway/src/aauth.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env/tests.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs
  • rsworkspace/crates/a2a-nats/src/gateway_ingress/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/error.rs
  • rsworkspace/crates/trogon-aauth-as/src/http.rs
  • rsworkspace/crates/trogon-aauth-as/src/http/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/policy/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/verify.rs
  • rsworkspace/crates/trogon-aauth-as/src/verify/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/agent/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/error/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/http/mod.rs
  • rsworkspace/crates/trogon-aauth-person/src/mission/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/pending/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/challenge/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/core/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/signer.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/verify_response/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/delegation/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/http_pop/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/jwks_http/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/mission.rs
  • rsworkspace/crates/trogon-aauth-verify/src/nats_pop.rs
  • rsworkspace/crates/trogon-aauth-verify/src/nats_pop/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/headers.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/login.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/mission.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/tests.rs
  • rsworkspace/crates/trogon-jwks-publisher/src/publisher.rs
🚧 Files skipped from review as they are similar to previous changes (16)
  • rsworkspace/crates/trogon-aauth-person/src/mission/tests.rs
  • rsworkspace/crates/a2a-nats/src/gateway_ingress/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/policy/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/mission.rs
  • rsworkspace/crates/trogon-aauth-as/src/http.rs
  • rsworkspace/crates/trogon-aauth-as/src/verify.rs
  • rsworkspace/crates/trogon-aauth-as/src/error.rs
  • rsworkspace/crates/trogon-aauth-person/src/pending/tests.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/signer.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs
  • rsworkspace/crates/trogon-aauth-person/src/http/mod.rs
  • rsworkspace/crates/a2a-gateway/src/aauth.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/dispatch.rs

Comment thread rsworkspace/crates/trogon-aauth-sdk/src/verify_response/tests.rs
yordis added 3 commits July 7, 2026 17:21
…smuggling and subagent identifier binding

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…e workspace lint

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…ons, and align a test name

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

@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: 1

🧹 Nitpick comments (4)
rsworkspace/crates/trogon-aauth-sdk/src/delegation.rs (1)

41-43: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Avoid building the full chain just to count/search it.

depth() and contains_agent() both call chain(), cloning every agent string into a Vec<String> before counting or scanning. An iterator over &Act nodes (no cloning, early-exit for contains_agent) would be more efficient, though the current chains are short enough that this is unlikely to matter in practice.

♻️ Possible refactor avoiding the Vec allocation
-    fn contains_agent(&self, agent_id: &str) -> bool {
-        self.chain().iter().any(|agent| agent == agent_id)
-    }
+    fn contains_agent(&self, agent_id: &str) -> bool {
+        let mut current = Some(self);
+        while let Some(act) = current {
+            if act.agent == agent_id {
+                return true;
+            }
+            current = act.act.as_deref();
+        }
+        false
+    }
🤖 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/trogon-aauth-sdk/src/delegation.rs` around lines 41 - 43,
The `contains_agent` helper currently builds the full `chain()` Vec and clones
every agent string before searching, which is unnecessary. Refactor
`Delegation::contains_agent` (and the related `depth()` logic if convenient) to
iterate directly over the underlying `Act` chain, so the lookup can
short-circuit without allocating or cloning. Keep the behavior the same, but use
an iterator-based traversal from the existing `Delegation`/`Act` structures
instead of calling `chain()`.
rsworkspace/crates/trogon-aauth-verify/src/jwks_http.rs (1)

274-278: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Error variant carries a formatted string, not a typed error.

JwksError::Transport(format!(...)) mirrors the existing pattern elsewhere in this file, but per coding guidelines errors must be typed (struct/enum variants), never String/format!(). A full fix means giving JwksError::Transport structured fields (e.g., iss: String, reason: TransportReason) across all call sites in this file, not just this arm.

As per coding guidelines: "Errors must be typed—use structs or enums, never String or format!(). Every error type must implement Display and std::error::Error."

🤖 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/trogon-aauth-verify/src/jwks_http.rs` around lines 274 -
278, `JwksError::Transport` is still being constructed from a formatted string
in `jwks_http.rs`, which violates the typed-error guideline. Update
`JwksError::Transport` to carry structured data (for example `iss: String` plus
a typed reason enum/struct) and implement `Display`/`Error` for the new error
type. Then replace this arm and the other `JwksError::Transport(format!(...))`
call sites in `jwks_http.rs` to construct the typed variant instead of embedding
message text.

Source: Coding guidelines

rsworkspace/crates/a2a-gateway/tests/aauth_roundtrip.rs (1)

655-672: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated ap_public_jwk construction block across the two new tests.

The ~18-line block building the EC public Jwk from ap_signing (point encoding, CommonParameters, AlgorithmParameters::EllipticCurve) is repeated verbatim in both resolve_nats_denies_expired_auth_token_with_valid_pop and resolve_nats_denies_mission_header_mismatching_claim, and likely elsewhere in this file given the number of resolve_nats tests added in this cohort. Extracting a small fn ap_public_jwk_from(signing: &SigningKey, kid: &str) -> Jwk helper (similar to the existing agent_fixture helper in this same file) would remove the duplication.

Also applies to: 729-746

🤖 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-gateway/tests/aauth_roundtrip.rs` around lines 655 -
672, The `ap_public_jwk` construction is duplicated across the new
`resolve_nats_*` tests, so extract it into a small helper in
`aauth_roundtrip.rs` (for example, an `ap_public_jwk_from` function that takes
the signing key and key id) and reuse that helper in both
`resolve_nats_denies_expired_auth_token_with_valid_pop` and
`resolve_nats_denies_mission_header_mismatching_claim`, following the pattern of
the existing `agent_fixture` helper to keep the EC/JWK setup in one place.
rsworkspace/crates/trogon-aauth-person/src/http/tests.rs (1)

168-204: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

FailingStore duplicates the identical test double already in server/tests.rs.

The FailingStore impl here is byte-for-byte identical to the one at rsworkspace/crates/trogon-aauth-person/src/server/tests.rs:518-558 (all nine PersonStateStore methods returning StoreError("backend down".into())). Consider hoisting this into a shared test-support module (the sibling trogon-aauth-as crate already uses this pattern via test_support.rs) so both test modules import one definition instead of maintaining two copies that can drift.

🤖 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/trogon-aauth-person/src/http/tests.rs` around lines 168 -
204, The FailingStore test double is duplicated and should be shared instead of
maintained in two places. Move the identical PersonStateStore failure stub used
by the http tests and the server tests into a common test-support module for the
trogon-aauth-person crate, then update the http::tests and server::tests modules
to import and use that shared FailingStore definition so the implementations
stay in sync.
🤖 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/trogon-aauth-person/src/http/tests.rs`:
- Around line 729-744: The missing-mission case in the permission flow is
currently being treated as a generic server failure, so update the error mapping
in the request handlers for permission, interaction, and audit to translate
PersonServerError::MissionNotFound into a 4xx client error instead of routing it
through server_error. Use the relevant handler/error-conversion path in the HTTP
layer to distinguish absent or unknown mission refs from real persistence
failures, and update the
permission_endpoint_without_mission_returns_mission_not_found test to assert the
client-error status.

---

Nitpick comments:
In `@rsworkspace/crates/a2a-gateway/tests/aauth_roundtrip.rs`:
- Around line 655-672: The `ap_public_jwk` construction is duplicated across the
new `resolve_nats_*` tests, so extract it into a small helper in
`aauth_roundtrip.rs` (for example, an `ap_public_jwk_from` function that takes
the signing key and key id) and reuse that helper in both
`resolve_nats_denies_expired_auth_token_with_valid_pop` and
`resolve_nats_denies_mission_header_mismatching_claim`, following the pattern of
the existing `agent_fixture` helper to keep the EC/JWK setup in one place.

In `@rsworkspace/crates/trogon-aauth-person/src/http/tests.rs`:
- Around line 168-204: The FailingStore test double is duplicated and should be
shared instead of maintained in two places. Move the identical PersonStateStore
failure stub used by the http tests and the server tests into a common
test-support module for the trogon-aauth-person crate, then update the
http::tests and server::tests modules to import and use that shared FailingStore
definition so the implementations stay in sync.

In `@rsworkspace/crates/trogon-aauth-sdk/src/delegation.rs`:
- Around line 41-43: The `contains_agent` helper currently builds the full
`chain()` Vec and clones every agent string before searching, which is
unnecessary. Refactor `Delegation::contains_agent` (and the related `depth()`
logic if convenient) to iterate directly over the underlying `Act` chain, so the
lookup can short-circuit without allocating or cloning. Keep the behavior the
same, but use an iterator-based traversal from the existing `Delegation`/`Act`
structures instead of calling `chain()`.

In `@rsworkspace/crates/trogon-aauth-verify/src/jwks_http.rs`:
- Around line 274-278: `JwksError::Transport` is still being constructed from a
formatted string in `jwks_http.rs`, which violates the typed-error guideline.
Update `JwksError::Transport` to carry structured data (for example `iss:
String` plus a typed reason enum/struct) and implement `Display`/`Error` for the
new error type. Then replace this arm and the other
`JwksError::Transport(format!(...))` call sites in `jwks_http.rs` to construct
the typed variant instead of embedding message text.
🪄 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: 3152ffd3-ac95-4328-b559-7bef04a255a3

📥 Commits

Reviewing files that changed from the base of the PR and between fd3d705 and 320beaf.

📒 Files selected for processing (44)
  • rsworkspace/crates/a2a-gateway/src/aauth/tests.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env/tests.rs
  • rsworkspace/crates/a2a-gateway/tests/aauth_roundtrip.rs
  • rsworkspace/crates/a2a-nats/src/gateway_ingress/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/error.rs
  • rsworkspace/crates/trogon-aauth-as/src/http.rs
  • rsworkspace/crates/trogon-aauth-as/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/trust/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/verify.rs
  • rsworkspace/crates/trogon-aauth-as/src/verify/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/agent.rs
  • rsworkspace/crates/trogon-aauth-person/src/agent/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/error.rs
  • rsworkspace/crates/trogon-aauth-person/src/http/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/capabilities.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/capabilities/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/delegation.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/delegation/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/verify_response/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/jwks_http.rs
  • rsworkspace/crates/trogon-aauth-verify/src/jwks_http/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/mission/tests.rs
  • rsworkspace/crates/trogon-aauth-verify/src/nats_pop.rs
  • rsworkspace/crates/trogon-aauth-verify/src/nats_pop/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/delegation.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/delegation/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/error.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/error/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/federation.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/federation/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/headers.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/headers/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/login.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/login/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/mission.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/mission/tests.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/person_server.rs
  • rsworkspace/crates/trogon-identity-types/src/aauth/person_server/tests.rs
  • rsworkspace/crates/trogon-jwks-publisher/src/provider/tests.rs
  • rsworkspace/crates/trogon-jwks-publisher/src/publisher.rs
  • rsworkspace/crates/trogon-jwks-publisher/src/publisher/tests.rs
🚧 Files skipped from review as they are similar to previous changes (16)
  • rsworkspace/crates/trogon-aauth-sdk/src/verify_response/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/trust/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/capabilities.rs
  • rsworkspace/crates/trogon-aauth-as/src/http.rs
  • rsworkspace/crates/trogon-aauth-as/src/error.rs
  • rsworkspace/crates/trogon-aauth-person/src/agent/tests.rs
  • rsworkspace/crates/a2a-gateway/src/aauth/tests.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/error.rs
  • rsworkspace/crates/trogon-aauth-person/src/server/tests.rs
  • rsworkspace/crates/trogon-aauth-person/src/agent.rs
  • rsworkspace/crates/a2a-gateway/src/runtime/aauth_env/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/verify/tests.rs
  • rsworkspace/crates/trogon-aauth-as/src/verify.rs
  • rsworkspace/crates/trogon-aauth-sdk/src/exchange/client.rs

Comment thread rsworkspace/crates/trogon-aauth-person/src/http/tests.rs
…nvalid_request instead of server_error

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis merged commit 5ee00cd into main Jul 8, 2026
8 checks passed
@yordis yordis deleted the yordis/feat-a2a-gateway-aauth-dispatch-wiring branch July 8, 2026 02:10
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