Skip to content

test(agent): e2e + registry + routing test suite - #1772

Open
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 12 commits into
masterfrom
feat/agent-tunnel-tests
Open

test(agent): e2e + registry + routing test suite#1772
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 12 commits into
masterfrom
feat/agent-tunnel-tests

Conversation

@irvingoujAtDevolution

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the agent-tunnel test suite under testsuite/tests/agent_tunnel/:

  • integration.rs — full QUIC end-to-end (CA → enroll → mTLS → control stream → ConnectRequest → echo) plus the domain-routing variant
  • registry.rsAgentRegistry unit tests (online/offline timeouts, route epoch handling, domain advertisement persistence, agent-info snapshot)
  • routing.rsRoutePlan::resolve / try_route decision matrix (explicit jet_agent_id, subnet/domain match, fallback, offline filtering, no-handle paths)

Why split out

The routing/upstream feature (#1741, since merged) kept its diff focused on production code. Tests live here so the test scaffolding diff doesn't muddle the feature review.

Test plan

  • cargo test -p testsuite --test integration_tests agent_tunnel:: — 25/25 pass locally

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) changed the title test(agent-tunnel): e2e + registry + routing test suite test(agent): e2e + registry + routing test suite Apr 29, 2026
@irvingoujAtDevolution
irvingouj@Devolutions (irvingoujAtDevolution) force-pushed the feat/quic-tunnel-2-routing branch 2 times, most recently from b4ec360 to a2b2ff5 Compare May 12, 2026 17:40
irvingouj@Devolutions (irvingoujAtDevolution) added a commit that referenced this pull request May 12, 2026
Address CBenoit's review on #1741: in addition to the `#[doc(hidden)]`
marker and the `_for_test` naming, gate `AgentPeer::set_last_seen_for_test`
and `set_received_at_for_test` behind `#[cfg(any(test, feature = "test-utils"))]`
so production builds of `devolutions-gateway` and `devolutions-agent` don't
compile these methods at all. Cross-crate test consumers (the workspace
`testsuite` crate carrying the agent-tunnel integration tests, in #1772)
opt in via `features = ["test-utils"]` on their `agent-tunnel` dev-dep.
Base automatically changed from feat/quic-tunnel-2-routing to master May 13, 2026 15:19
@irvingoujAtDevolution
irvingouj@Devolutions (irvingoujAtDevolution) force-pushed the feat/agent-tunnel-tests branch 3 times, most recently from 8887df1 to c2da5a9 Compare May 19, 2026 19:05
@irvingoujAtDevolution
irvingouj@Devolutions (irvingoujAtDevolution) marked this pull request as ready for review May 25, 2026 21:10
- testsuite/tests/agent_tunnel/integration.rs: full QUIC e2e (CA →
  enroll → mTLS → control stream → ConnectRequest → echo) and a
  domain-routing variant.
- testsuite/tests/agent_tunnel/registry.rs: AgentRegistry unit tests
  covering online/offline timeouts, route epoch handling (replace vs
  refresh vs ignore stale), domain advertisement persistence, and the
  agent-info snapshot.
- testsuite/tests/agent_tunnel/routing.rs: RoutePlan::resolve / try_route
  decision matrix — explicit jet_agent_id, subnet match, domain match,
  fallback to direct, offline filtering, and the no-handle paths.

Also includes the read_cert_chain rewrite from #1771 (needed for the
e2e tests to parse the rcgen-produced PEM); once #1771 lands this
collapses to just the test files.
…iants

Backfills coverage that the original test suite (#1741-era) predates:

- New `common.rs` consolidates the QUIC + mTLS test scaffolding so all
  E2E tests share one `bind_test_listener` helper instead of duplicating
  ~80 lines per test.

- New `cert.rs` pins three invariants of `agent-tunnel/src/cert.rs`:
  - `sign_agent_csr` must encode the caller-passed agent_id in the URN
    SAN, *ignoring* the CSR's Common Name (#1775 review feedback —
    prevents a compromised agent from impersonating via CSR subject).
  - `extract_agent_id_from_pem` round-trips a freshly signed cert.
  - `extract_agent_id_from_pem` rejects a cert with no urn:uuid SAN
    (e.g. the CA root cert).

- Extra `routing.rs` cases against a live `AgentTunnelHandle`:
  - `route_and_connect` errors on empty candidate slice.
  - `try_route` with handle present and no match returns `Ok(None)`.
  - `try_route` with handle present and missing explicit agent_id errors
    rather than silently falling back to direct.

- New `cert_renewal_preserves_mtls_identity_e2e` runs the full QUIC
  `CertRenewalRequest` → `CertRenewalResponse::Success` round-trip with
  a renewal CSR filed under `CN=evil-impersonator`. Asserts the renewed
  cert still encodes the mTLS-authenticated `agent_id` — guards the
  #1775 handler's "never trust the CSR subject" comment with a test.

32 tests now pass; 3 parallel runs verified stable (~0.3s each).
…dvertise

`ctrl.send(&RouteAdvertise)` only guarantees the message is on the wire,
not that the gateway has processed it and updated `peer.route_state()`.
A fixed 200ms `tokio::time::sleep` was racy on slow/loaded CI runners.

Replace the three call sites with `wait_for_route_advertised`, a 10ms
poll loop that exits as soon as the agent appears in the registry with
`route_state().epoch >= min_epoch`, or panics with a clear message
after 5s. Default `RouteAdvertisementState` has epoch 0, so any
successful RouteAdvertise bumps it to >= 1.

Side effect: the e2e tests finish in ~0.16s instead of ~0.32s because
they no longer eat the worst-case fixed delay.
Exercise registration, routing, KDC forwarding, certificate renewal, and real Agent processes over QUIC. Add a Docker scenario that isolates DNS and IP targets from the Gateway so direct connections cannot create false positives.
Run the ignored Docker scenario on Ubuntu and include it in the required CI success gate.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds broad agent-tunnel coverage across routing, QUIC integration, certificate renewal, KDC forwarding, and Docker-isolated real-agent scenarios.

Changes:

  • Adds agent-tunnel integration and routing tests.
  • Adds Docker-based end-to-end testing and CI execution.
  • Extends test configuration and generalizes agent stream helpers.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
.github/workflows/ci.yml Runs the Docker end-to-end test.
Cargo.lock Records new test dependencies.
devolutions-agent/src/tunnel.rs Enables stream-based unit tests and tests renewal/proxy behavior.
testsuite/Cargo.toml Adds agent-tunnel test dependencies.
testsuite/src/cli.rs Adds asynchronous agent process launching.
testsuite/src/dgw_config.rs Supports tunnel-specific gateway configuration.
testsuite/tests/agent_tunnel/cert.rs Tests certificate identity handling.
testsuite/tests/agent_tunnel/common.rs Provides shared QUIC fixtures.
testsuite/tests/agent_tunnel/integration.rs Tests routed and direct upstream flows.
testsuite/tests/agent_tunnel/kdc.rs Tests KDC routing behavior.
testsuite/tests/agent_tunnel/mod.rs Registers test modules; advertised registry suite is absent.
testsuite/tests/agent_tunnel/routing.rs Tests routing decisions and fallback behavior.
testsuite/tests/cli/agent/mod.rs Registers agent tunnel CLI tests.
testsuite/tests/cli/agent/tunnel.rs Adds real-process and Docker end-to-end tests.
testsuite/tests/main.rs Registers the agent-tunnel suite.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1 to +5
mod cert;
mod common;
mod integration;
mod kdc;
mod routing;
Linux Docker rejects static container addresses on networks without a user-configured subnet. Derive a private /24 from the test ID so the target and Agent containers keep stable addresses.
Keep the real Docker coverage while removing test-only seams from the Agent runtime.
Limit APT request stalls and leave enough time for the real Docker end-to-end test.
Bound each APT attempt so mirror stalls cannot consume the entire end-to-end job.
Bound and retry both APT phases so a stalled package mirror cannot skip the end-to-end test.
The Agent Tunnel test dependency tree does not require libsystemd, so avoid the unreliable APT mirror entirely.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants