Files
VerseVDI-Data-Plane/core/tests/gateway_oracle.rs
T

807 lines
35 KiB
Rust

use std::fs;
use std::process::{Child, Command, Stdio};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use base64::engine::general_purpose::STANDARD;
use base64::Engine as _;
use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
use rustls::sign::SigningKey;
use rustls::SignatureScheme;
use serde::Deserialize;
use versevdi_core::error::CoreError;
use versevdi_core::transport::{
connect, connect_with_cancellation, AdmissionSigner, Cancellation, Signers, TlsEd25519Signer,
};
use versevdi_core::wire::{ConnectionManifest, NativeTunnelCredential};
const ORACLE_SOURCE: &str = r#"
package main
import (
"bytes"
"context"
"crypto/ed25519"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"math/big"
"os"
"sync"
"time"
gateway "git.sechmachine.io.vn/sechmachine/VerseVDI-Data-Plane/gateway"
protocol "git.sechmachine.io.vn/sechmachine/VerseVDI-Protocol/gen/go/protocol"
)
type admission struct {
mu sync.Mutex
lastTranscript []byte
reusable bool
failWorkOnce bool
authority protocol.SessionAuthority
work protocol.ProviderSessionWork
public ed25519.PublicKey
}
func (a *admission) Admit(_ context.Context, request protocol.TunnelAdmissionRequest) (protocol.SessionAuthority, error) {
signature, err := base64.RawURLEncoding.DecodeString(request.DeviceSignature)
transcript := request.DeviceAdmissionTranscript()
if err != nil || !ed25519.Verify(a.public, transcript, signature) {
return protocol.SessionAuthority{}, gateway.ErrAdmissionRejected
}
a.mu.Lock(); defer a.mu.Unlock()
if !a.reusable && bytes.Equal(a.lastTranscript, transcript) { return protocol.SessionAuthority{}, gateway.ErrAdmissionRejected }
a.lastTranscript = append(a.lastTranscript[:0], transcript...)
return a.authority, nil
}
func (a *admission) ProviderWork(context.Context, protocol.SessionAuthority) (protocol.ProviderSessionWork, error) {
a.mu.Lock(); defer a.mu.Unlock()
if a.failWorkOnce { a.failWorkOnce = false; return protocol.ProviderSessionWork{}, context.DeadlineExceeded }
return a.work, nil
}
func (a *admission) Release(context.Context, protocol.SessionAuthority) error { return nil }
type provider struct{}
type session struct { state protocol.ProviderState; video chan gateway.ProviderMedia; audio chan gateway.ProviderMedia; events chan gateway.ProviderEvent }
func (provider) Start(_ context.Context, request gateway.LaunchRequest) (gateway.ProviderSession, error) {
return &session{state: protocol.ProviderState{Version:"1", SessionID:request.SessionID, State:gateway.ProviderStateReady, Channels:[]string{"video","audio","input","feedback"}}, video:make(chan gateway.ProviderMedia), audio:make(chan gateway.ProviderMedia), events:make(chan gateway.ProviderEvent)}, nil
}
func (s *session) Ready(context.Context) error { return nil }
func (s *session) Video() <-chan gateway.ProviderMedia { return s.video }
func (s *session) Audio() <-chan gateway.ProviderMedia { return s.audio }
func (s *session) Events() <-chan gateway.ProviderEvent { return s.events }
func (s *session) Input(context.Context, gateway.InputEvent) error { return nil }
func (s *session) Feedback(context.Context, gateway.Feedback) error { return nil }
func (s *session) ReadClipboard(context.Context) (string, error) { return "", errors.New("disabled") }
func (s *session) WriteClipboard(context.Context, string) error { return errors.New("disabled") }
func (s *session) Telemetry() gateway.ProviderTelemetry { return gateway.ProviderTelemetry{State:s.state.State} }
func (s *session) ReleaseAll(context.Context) error { return nil }
func (s *session) Terminate(context.Context) error { return nil }
func (s *session) State() protocol.ProviderState { return s.state }
func makeCertificate(parent *x509.Certificate, parentKey ed25519.PrivateKey, serial int64, dns string, usage x509.ExtKeyUsage, isCA bool) ([]byte, ed25519.PrivateKey) {
public, private, err := ed25519.GenerateKey(rand.Reader); if err != nil { panic(err) }
template := &x509.Certificate{SerialNumber:big.NewInt(serial), Subject:pkix.Name{CommonName:dns}, DNSNames:[]string{dns}, NotBefore:time.Now().Add(-time.Hour), NotAfter:time.Now().Add(time.Hour), IsCA:isCA, BasicConstraintsValid:true, KeyUsage:x509.KeyUsageDigitalSignature}
if isCA { template.KeyUsage |= x509.KeyUsageCertSign } else { template.ExtKeyUsage = []x509.ExtKeyUsage{usage} }
if parent == nil { parent = template; parentKey = private }
der, err := x509.CreateCertificate(rand.Reader, template, parent, public, parentKey); if err != nil { panic(err) }
return der, private
}
func pemCert(ders ...[]byte) string { var out []byte; for _, der := range ders { out = append(out, pem.EncodeToMemory(&pem.Block{Type:"CERTIFICATE",Bytes:der})...) }; return string(out) }
func main() {
readyPath, stopPath := os.Args[1], os.Args[2]
mode := os.Getenv("VERSEVDI_RUST_ORACLE_MODE")
caDER, caKey := makeCertificate(nil, nil, 1, "Verse Rust Oracle CA", 0, true)
ca, err := x509.ParseCertificate(caDER); if err != nil { panic(err) }
serverDER, serverKey := makeCertificate(ca, caKey, 2, "gateway.test", x509.ExtKeyUsageServerAuth, false)
clientDER, clientKey := makeCertificate(ca, caKey, 3, "client.test", x509.ExtKeyUsageClientAuth, false)
_, admissionKey := makeCertificate(ca, caKey, 6, "admission.test", x509.ExtKeyUsageClientAuth, false)
badCADER, _ := makeCertificate(nil, nil, 4, "Wrong CA", 0, true)
_, wrongClientKey := makeCertificate(ca, caKey, 5, "wrong-client.test", x509.ExtKeyUsageClientAuth, false)
pool := x509.NewCertPool(); pool.AddCert(ca)
server := &tls.Config{MinVersion:tls.VersionTLS13, MaxVersion:tls.VersionTLS13, Certificates:[]tls.Certificate{{Certificate:[][]byte{serverDER,caDER},PrivateKey:serverKey}}, ClientAuth:tls.RequireAndVerifyClientCert, ClientCAs:pool}
expiry := time.Now().Add(5*time.Minute).UTC().Truncate(time.Second).Format(time.RFC3339)
authority := protocol.SessionAuthority{Version:"1",SessionID:"session-1",GatewayID:"gateway-1",Audience:"versevdi-gateway",ExpiresAt:expiry,Capabilities:gateway.DefaultCapabilities(),ProviderProfile:gateway.ProviderProfileApollo,ProviderIdentity:"oracle#sha256:fixture"}
if mode == "session" { authority.SessionID = "other-session" }
if mode == "gateway" { authority.GatewayID = "other-gateway" }
if mode == "audience" { authority.Audience = "other-audience" }
if mode == "reconnect" { authority.ReconnectSequence = 1 }
if mode == "expiry" { authority.ExpiresAt = time.Now().Add(-time.Minute).UTC().Truncate(time.Second).Format(time.RFC3339) }
if mode == "capability" { authority.Capabilities.ClientDecode = []string{"hevc-opus"} }
if mode == "alpn" { server.NextProtos = []string{"wrong-alpn"} }
work := protocol.ProviderSessionWork{Version:"1",SessionID:authority.SessionID,GatewayID:authority.GatewayID,ExpiresAt:expiry,ProviderProfile:gateway.ProviderProfileApollo,ProviderIdentity:authority.ProviderIdentity,PolicyVersionID:"policy-1",StreamPolicy:protocol.ProviderStreamPolicy{ResolutionWidth:1920,ResolutionHeight:1080,Fps:60,Codec:"H264",BitrateKbps:8000,AudioEnabled:true},ApplicationID:"1",ClientID:"client",ManagementHost:"provider.invalid",ManagementPort:47990,StreamHost:"provider.invalid",StreamPort:47984,ClientCertificatePem:"certificate",ClientPrivateKeyPem:"private-key",ServerCertificatePem:"certificate",ClipboardPolicy:protocol.ClipboardPolicy{MaxTextBytes:65536,MaxUpdatesPerMinute:30}}
replayGuard := &admission{authority:authority,work:work,public:admissionKey.Public().(ed25519.PublicKey)}
replayRequest := protocol.TunnelAdmissionRequest{Version:"1",SessionID:"session-1",GatewayID:"gateway-1",Audience:"versevdi-gateway",Grant:"ggggggggggggggggggggggggggggggggggggggggggg",ClientNonce:"bm9uY2UtZm9yLXJlcGxheQ",Capabilities:gateway.DefaultCapabilities()}
replayRequest.DeviceSignature = base64.RawURLEncoding.EncodeToString(ed25519.Sign(admissionKey,replayRequest.DeviceAdmissionTranscript()))
_, firstReplayErr := replayGuard.Admit(context.Background(),replayRequest)
_, secondReplayErr := replayGuard.Admit(context.Background(),replayRequest)
replayRejected := firstReplayErr == nil && errors.Is(secondReplayErr,gateway.ErrAdmissionRejected)
admissionService := &admission{authority:authority,work:work,public:admissionKey.Public().(ed25519.PublicKey),reusable:mode == "reusable",failWorkOnce:mode == "post-retryable"}
newService := func() *gateway.Server {
service, err := gateway.NewServer(gateway.ServerConfig{ListenAddress:"127.0.0.1:0",TLSConfig:server,GatewayID:authority.GatewayID,Admission:admissionService,Provider:provider{}}); if err != nil { panic(err) }
return service
}
service := newService()
services := []*gateway.Server{service}
addresses := []string{service.Addr().String()}
if mode == "retryable" {
draining := newService()
draining.BeginDrain()
services = []*gateway.Server{draining, service}
addresses = []string{draining.Addr().String(), service.Addr().String()}
}
if mode == "post-retryable" {
second := newService()
services = []*gateway.Server{service, second}
addresses = []string{service.Addr().String(), second.Addr().String()}
}
ctx, cancel := context.WithCancel(context.Background()); defer cancel()
done := make(chan error,len(services)); for _, current := range services { go func(server *gateway.Server){done <- server.Serve(ctx)}(current) }
keyDER, err := x509.MarshalPKCS8PrivateKey(clientKey); if err != nil { panic(err) }
admissionKeyDER, err := x509.MarshalPKCS8PrivateKey(admissionKey); if err != nil { panic(err) }
manifest := map[string]any{"version":"1","purpose":"launch","session_id":"session-1","reconnect_sequence":0,"gateway":map[string]any{"id":"gateway-1","addresses":addresses,"public_identity":"gateway.test"},"tunnel":map[string]any{"versions":[]string{"verse-gateway-v1/1"},"features":[]string{"control.v1"}},"profile":map[string]any{"id":"standard","bounds":map[string]any{"minimum_kbps":1000,"target_kbps":5000,"maximum_kbps":10000},"display_mode":map[string]any{"resolution_width":1920,"resolution_height":1080,"fps":60}},"grant":map[string]any{"opaque_value":"ggggggggggggggggggggggggggggggggggggggggggg","expires_at":"2099-01-01T00:00:00Z","audience":"versevdi-gateway"},"correlation_id":"oracle"}
credential := map[string]any{"client_device_id":"device","device_key_id":"key","certificate_chain_pem":pemCert(clientDER,caDER),"trust_bundle_pem":pemCert(caDER),"expires_at":"2099-01-01T00:00:00Z"}
manifestJSON,_ := json.Marshal(manifest); credentialJSON,_ := json.Marshal(credential)
wrongKeyDER, err := x509.MarshalPKCS8PrivateKey(wrongClientKey); if err != nil { panic(err) }
serverKeyDER, err := x509.MarshalPKCS8PrivateKey(serverKey); if err != nil { panic(err) }
ready,_ := json.Marshal(map[string]any{"manifest":string(manifestJSON),"credential":string(credentialJSON),"admission_key":base64.StdEncoding.EncodeToString(admissionKeyDER),"client_key":base64.StdEncoding.EncodeToString(keyDER),"wrong_client_key":base64.StdEncoding.EncodeToString(wrongKeyDER),"server_key":base64.StdEncoding.EncodeToString(serverKeyDER),"server_chain":pemCert(serverDER,caDER),"bad_trust":pemCert(badCADER),"replay_rejected":replayRejected})
if err := os.WriteFile(readyPath,ready,0600); err != nil { panic(err) }
for { if _, err := os.Stat(stopPath); err == nil { break }; time.Sleep(10*time.Millisecond) }
cancel(); for _, current := range services { _ = current.Close() }; for range services { <-done }
}
"#;
#[derive(Deserialize)]
struct Ready {
manifest: String,
credential: String,
admission_key: String,
client_key: String,
wrong_client_key: String,
server_key: String,
server_chain: String,
bad_trust: String,
replay_rejected: bool,
}
struct Oracle {
_serial: std::sync::MutexGuard<'static, ()>,
child: Child,
directory: std::path::PathBuf,
ready: Ready,
}
impl Oracle {
fn start(mode: &str) -> Self {
static SERIAL: Mutex<()> = Mutex::new(());
static NEXT: AtomicUsize = AtomicUsize::new(1);
let serial = SERIAL
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let directory = std::env::temp_dir().join(format!(
"versevdi-rust-gateway-oracle-{}-{}",
std::process::id(),
NEXT.fetch_add(1, Ordering::Relaxed)
));
fs::create_dir(&directory).expect("create oracle directory");
let source = directory.join("main.go");
let ready_path = directory.join("ready.json");
let stop_path = directory.join("stop");
fs::write(&source, ORACLE_SOURCE).expect("write oracle source");
let child = Command::new("go")
.args(["run", source.to_str().expect("source path is UTF-8")])
.arg(&ready_path)
.arg(&stop_path)
.env("VERSEVDI_RUST_ORACLE_MODE", mode)
.current_dir(env!("CARGO_MANIFEST_DIR"))
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("start Go gateway oracle");
let deadline = Instant::now() + Duration::from_secs(20);
while Instant::now() < deadline {
if let Ok(bytes) = fs::read(&ready_path) {
if let Ok(ready) = serde_json::from_slice(&bytes) {
return Self {
_serial: serial,
child,
directory,
ready,
};
}
}
thread::sleep(Duration::from_millis(10));
}
let output = child.wait_with_output().expect("collect Go oracle output");
panic!(
"Go gateway oracle did not become ready: status={} stdout={} stderr={}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
}
impl Drop for Oracle {
fn drop(&mut self) {
let _ = fs::write(self.directory.join("stop"), []);
let _ = self.child.wait();
let _ = fs::remove_dir_all(&self.directory);
}
}
fn test_key(encoded: &str) -> Arc<dyn SigningKey> {
let der = STANDARD.decode(encoded).expect("decode test key");
rustls::crypto::ring::default_provider()
.key_provider
.load_private_key(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(der)))
.expect("load ephemeral Ed25519 test key")
}
#[test]
fn callback_ed25519_signer_completes_tls13_quic_admission_without_private_key_input() {
let oracle = Oracle::start("");
let manifest = ConnectionManifest::decode(oracle.ready.manifest.as_bytes()).expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let admission_key = test_key(&oracle.ready.admission_key);
let tls_key = test_key(&oracle.ready.client_key);
let admission_inputs = Arc::new(Mutex::new(Vec::new()));
let tls_inputs = Arc::new(Mutex::new(Vec::new()));
let admission_calls = Arc::new(AtomicUsize::new(0));
let tls_calls = Arc::new(AtomicUsize::new(0));
let sign = |key: Arc<dyn SigningKey>, input: &[u8]| -> Result<[u8; 64], CoreError> {
let signer = key
.choose_scheme(&[SignatureScheme::ED25519])
.ok_or(CoreError::Tls)?;
signer
.sign(input)
.map_err(|_| CoreError::Tls)?
.try_into()
.map_err(|_| CoreError::Tls)
};
let admission = {
let key = Arc::clone(&admission_key);
let inputs = Arc::clone(&admission_inputs);
let calls = Arc::clone(&admission_calls);
AdmissionSigner::new(move |input| {
calls.fetch_add(1, Ordering::SeqCst);
*inputs.lock().expect("admission inputs") = input.to_vec();
sign(Arc::clone(&key), input)
})
};
let tls = {
let key = Arc::clone(&tls_key);
let inputs = Arc::clone(&tls_inputs);
let calls = Arc::clone(&tls_calls);
TlsEd25519Signer::new(move |input| {
calls.fetch_add(1, Ordering::SeqCst);
*inputs.lock().expect("TLS inputs") = input.to_vec();
sign(Arc::clone(&key), input)
})
};
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let session = runtime
.block_on(connect(
&manifest,
&credential,
Signers::new(admission, tls),
"2026-08-12T00:00:00Z",
Duration::from_secs(10),
))
.expect("production Go gateway admission");
assert_eq!(session.authority().session_id(), "session-1");
assert_eq!(admission_calls.load(Ordering::SeqCst), 1);
assert!(tls_calls.load(Ordering::SeqCst) >= 1);
assert!(admission_inputs
.lock()
.expect("admission transcript")
.starts_with(b"versevdi/tunnel-admission/v1"));
assert_ne!(
*admission_inputs.lock().expect("admission transcript"),
*tls_inputs.lock().expect("TLS transcript")
);
runtime.block_on(session.close());
}
fn signer(key: Arc<dyn SigningKey>) -> impl Fn(&[u8]) -> Result<[u8; 64], CoreError> {
move |input| {
key.choose_scheme(&[SignatureScheme::ED25519])
.ok_or(CoreError::Tls)?
.sign(input)
.map_err(|_| CoreError::Tls)?
.try_into()
.map_err(|_| CoreError::Tls)
}
}
fn connect_oracle(
oracle: &Oracle,
admission_key: &str,
tls_key: &str,
mutate_manifest: impl FnOnce(&mut serde_json::Value),
mutate_credential: impl FnOnce(&mut serde_json::Value),
) -> Result<versevdi_core::transport::TransportSession, CoreError> {
let mut manifest: serde_json::Value =
serde_json::from_str(&oracle.ready.manifest).expect("manifest JSON");
let mut credential: serde_json::Value =
serde_json::from_str(&oracle.ready.credential).expect("credential JSON");
mutate_manifest(&mut manifest);
mutate_credential(&mut credential);
let manifest =
ConnectionManifest::decode(&serde_json::to_vec(&manifest).expect("encode manifest"))?;
let credential = NativeTunnelCredential::decode(
&serde_json::to_vec(&credential).expect("encode credential"),
)?;
let runtime = tokio::runtime::Runtime::new().expect("runtime");
runtime.block_on(connect(
&manifest,
&credential,
Signers::new(
AdmissionSigner::new(signer(test_key(admission_key))),
TlsEd25519Signer::new(signer(test_key(tls_key))),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
}
#[test]
fn production_gateway_rejects_tls_and_admission_identity_mismatches() {
for case in [
"wrong-key",
"wrong-signature",
"wrong-leaf",
"wrong-sni",
"wrong-root",
"wrong-alpn",
] {
let oracle = Oracle::start("");
let admission_key = &oracle.ready.admission_key;
let tls_key = &oracle.ready.client_key;
let wrong = &oracle.ready.wrong_client_key;
let result = match case {
"wrong-key" => connect_oracle(&oracle, admission_key, wrong, |_| {}, |_| {}),
"wrong-signature" => connect_oracle(&oracle, wrong, tls_key, |_| {}, |_| {}),
"wrong-leaf" => connect_oracle(
&oracle,
admission_key,
&oracle.ready.server_key,
|_| {},
|credential| {
credential["certificate_chain_pem"] = oracle.ready.server_chain.clone().into();
},
),
"wrong-sni" => connect_oracle(
&oracle,
admission_key,
tls_key,
|manifest| manifest["gateway"]["public_identity"] = "other.test".into(),
|_| {},
),
"wrong-root" => connect_oracle(
&oracle,
admission_key,
tls_key,
|_| {},
|credential| credential["trust_bundle_pem"] = oracle.ready.bad_trust.clone().into(),
),
"wrong-alpn" => {
drop(oracle);
let oracle = Oracle::start("alpn");
connect_oracle(
&oracle,
&oracle.ready.admission_key,
&oracle.ready.client_key,
|_| {},
|_| {},
)
}
_ => unreachable!(),
};
let expected = if case == "wrong-signature" {
CoreError::AuthorityRejected
} else {
CoreError::Tls
};
assert_eq!(result.err(), Some(expected), "wrong error for {case}");
}
}
#[test]
fn production_gateway_and_rust_reject_authority_binding_and_capability_mismatches() {
for mode in [
"session",
"gateway",
"audience",
"reconnect",
"capability",
"expiry",
] {
let oracle = Oracle::start(mode);
let result = connect_oracle(
&oracle,
&oracle.ready.admission_key,
&oracle.ready.client_key,
|_| {},
|_| {},
);
assert!(result.is_err(), "{mode} mismatch unexpectedly connected");
}
}
#[test]
fn signer_purposes_are_not_interchangeable() {
let oracle = Oracle::start("");
let admission_key = test_key(&oracle.ready.admission_key);
let tls_key = test_key(&oracle.ready.client_key);
let manifest = ConnectionManifest::decode(oracle.ready.manifest.as_bytes()).expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let admission = AdmissionSigner::new(move |message| {
if !message.starts_with(b"versevdi/tunnel-admission/v1") {
return Err(CoreError::AuthorityRejected);
}
signer(Arc::clone(&admission_key))(message)
});
let tls = TlsEd25519Signer::new(move |message| {
if message.starts_with(b"versevdi/tunnel-admission/v1") {
return Err(CoreError::Tls);
}
signer(Arc::clone(&tls_key))(message)
});
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let session = runtime
.block_on(connect(
&manifest,
&credential,
Signers::new(admission, tls),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.expect("purpose-separated signers");
runtime.block_on(session.close());
}
#[test]
fn swapping_admission_and_tls_signer_purposes_is_rejected() {
let oracle = Oracle::start("");
let result = connect_oracle(
&oracle,
&oracle.ready.client_key,
&oracle.ready.admission_key,
|_| {},
|_| {},
);
assert!(
result.is_err(),
"one interchangeable key was accepted for both signer purposes"
);
}
fn recording_signers(
admission_key: Arc<dyn SigningKey>,
tls_key: Arc<dyn SigningKey>,
transcripts: Arc<Mutex<Vec<Vec<u8>>>>,
) -> Signers {
Signers::new(
AdmissionSigner::new(move |message| {
transcripts
.lock()
.expect("admission transcripts")
.push(message.to_vec());
signer(Arc::clone(&admission_key))(message)
}),
TlsEd25519Signer::new(signer(tls_key)),
)
}
#[test]
fn fresh_nonce_changes_transcript_and_oracle_rejects_identical_replay() {
let transcripts = Arc::new(Mutex::new(Vec::new()));
let runtime = tokio::runtime::Runtime::new().expect("runtime");
for _ in 0..2 {
let oracle = Oracle::start("");
let manifest =
ConnectionManifest::decode(oracle.ready.manifest.as_bytes()).expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let session = runtime
.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::clone(&transcripts),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.expect("fresh nonce admission");
runtime.block_on(session.close());
assert!(
oracle.ready.replay_rejected,
"oracle accepted identical replay"
);
}
let transcripts = transcripts.lock().expect("transcripts");
assert_eq!(transcripts.len(), 2);
assert_ne!(transcripts[0], transcripts[1], "nonce was reused");
}
#[test]
fn overall_deadline_cancels_an_unresponsive_manifest_address() {
let oracle = Oracle::start("");
let socket = std::net::UdpSocket::bind("127.0.0.1:0").expect("bind blackhole");
let mut manifest: serde_json::Value =
serde_json::from_str(&oracle.ready.manifest).expect("manifest JSON");
manifest["gateway"]["addresses"] =
serde_json::json!([socket.local_addr().expect("blackhole address").to_string()]);
let manifest =
ConnectionManifest::decode(&serde_json::to_vec(&manifest).expect("encode manifest"))
.expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let started = Instant::now();
let result = runtime.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::new(Mutex::new(Vec::new())),
),
"2026-08-12T00:00:00Z",
Duration::from_millis(150),
));
assert_eq!(result.err(), Some(CoreError::Cancelled));
assert!(started.elapsed() < Duration::from_secs(2));
}
#[test]
fn overall_deadline_includes_synchronous_admission_signing() {
let oracle = Oracle::start("");
let manifest = ConnectionManifest::decode(oracle.ready.manifest.as_bytes()).expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let admission_key = test_key(&oracle.ready.admission_key);
let tls_key = test_key(&oracle.ready.client_key);
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let started = Instant::now();
let result = runtime.block_on(connect(
&manifest,
&credential,
Signers::new(
AdmissionSigner::new(move |message| {
thread::sleep(Duration::from_millis(100));
signer(Arc::clone(&admission_key))(message)
}),
TlsEd25519Signer::new(signer(tls_key)),
),
"2026-08-12T00:00:00Z",
Duration::from_millis(25),
));
assert_eq!(result.err(), Some(CoreError::Cancelled));
assert!(started.elapsed() < Duration::from_secs(2));
}
#[test]
fn explicit_cancellation_interrupts_network_wait() {
let oracle = Oracle::start("");
let socket = std::net::UdpSocket::bind("127.0.0.1:0").expect("bind blackhole");
let mut manifest: serde_json::Value =
serde_json::from_str(&oracle.ready.manifest).expect("manifest JSON");
manifest["gateway"]["addresses"] =
serde_json::json!([socket.local_addr().expect("blackhole address").to_string()]);
let manifest =
ConnectionManifest::decode(&serde_json::to_vec(&manifest).expect("encode manifest"))
.expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let cancellation = Cancellation::new();
let trigger = cancellation.clone();
let canceller = thread::spawn(move || {
thread::sleep(Duration::from_millis(25));
trigger.cancel();
});
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let started = Instant::now();
let result = runtime.block_on(connect_with_cancellation(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::new(Mutex::new(Vec::new())),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
&cancellation,
));
canceller.join().expect("canceller");
assert_eq!(result.err(), Some(CoreError::Cancelled));
assert!(started.elapsed() < Duration::from_secs(2));
}
#[test]
fn blackholed_first_manifest_address_does_not_starve_live_second_address() {
let oracle = Oracle::start("");
let socket = std::net::UdpSocket::bind("127.0.0.1:0").expect("bind blackhole");
let mut manifest: serde_json::Value =
serde_json::from_str(&oracle.ready.manifest).expect("manifest JSON");
let live = manifest["gateway"]["addresses"][0].clone();
manifest["gateway"]["addresses"] = serde_json::json!([
socket.local_addr().expect("blackhole address").to_string(),
live,
]);
let manifest =
ConnectionManifest::decode(&serde_json::to_vec(&manifest).expect("encode manifest"))
.expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let session = runtime
.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::new(Mutex::new(Vec::new())),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.expect("live second manifest address");
runtime.block_on(session.close());
}
#[test]
fn multi_record_first_manifest_address_does_not_starve_live_second_address() {
let oracle = Oracle::start("");
let socket = std::net::UdpSocket::bind("127.0.0.1:0").expect("bind blackhole");
let port = socket.local_addr().expect("blackhole address").port();
let mut manifest: serde_json::Value =
serde_json::from_str(&oracle.ready.manifest).expect("manifest JSON");
let live = manifest["gateway"]["addresses"][0].clone();
manifest["gateway"]["addresses"] = serde_json::json!([format!("localhost:{port}"), live]);
let manifest =
ConnectionManifest::decode(&serde_json::to_vec(&manifest).expect("encode manifest"))
.expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let session = runtime
.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::new(Mutex::new(Vec::new())),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.expect("live second address after multi-record first address");
runtime.block_on(session.close());
}
#[test]
fn invalid_first_manifest_address_does_not_block_live_second_address() {
let oracle = Oracle::start("");
let mut manifest: serde_json::Value =
serde_json::from_str(&oracle.ready.manifest).expect("manifest JSON");
let live = manifest["gateway"]["addresses"][0].clone();
manifest["gateway"]["addresses"] = serde_json::json!(["127.0.0.1:0", live]);
let manifest =
ConnectionManifest::decode(&serde_json::to_vec(&manifest).expect("encode manifest"))
.expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let session = runtime
.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::new(Mutex::new(Vec::new())),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.expect("live address after resolution failure");
runtime.block_on(session.close());
}
#[test]
fn retryable_stable_error_advances_to_live_manifest_address() {
let oracle = Oracle::start("retryable");
let manifest = ConnectionManifest::decode(oracle.ready.manifest.as_bytes()).expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let session = runtime
.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::new(Mutex::new(Vec::new())),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.expect("retryable draining response advanced to live address");
runtime.block_on(session.close());
}
#[test]
fn post_admission_retry_uses_a_fresh_signed_nonce() {
let oracle = Oracle::start("post-retryable");
let manifest = ConnectionManifest::decode(oracle.ready.manifest.as_bytes()).expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let transcripts = Arc::new(Mutex::new(Vec::new()));
let runtime = tokio::runtime::Runtime::new().expect("runtime");
let session = runtime
.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::clone(&transcripts),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.expect("post-admission retry used a fresh request");
runtime.block_on(session.close());
let transcripts = transcripts.lock().expect("transcripts");
assert_eq!(transcripts.len(), 2);
assert_ne!(transcripts[0], transcripts[1]);
}
#[test]
fn repeated_production_gateway_admissions_remain_bounded() {
let runtime = tokio::runtime::Runtime::new().expect("runtime");
for index in 0..10 {
let oracle = Oracle::start("reusable");
let manifest =
ConnectionManifest::decode(oracle.ready.manifest.as_bytes()).expect("manifest");
let credential =
NativeTunnelCredential::decode(oracle.ready.credential.as_bytes()).expect("credential");
let session = runtime
.block_on(connect(
&manifest,
&credential,
recording_signers(
test_key(&oracle.ready.admission_key),
test_key(&oracle.ready.client_key),
Arc::new(Mutex::new(Vec::new())),
),
"2026-08-12T00:00:00Z",
Duration::from_secs(5),
))
.unwrap_or_else(|error| panic!("stress admission {index}: {error:?}"));
runtime.block_on(session.close());
}
}