Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ docker = { max-threads = 4 }
# so the group exists only to keep the plain-cargo path calm and stays
# serialized out of caution rather than need.
keyring = { max-threads = 1 }
# Every mDNS discovery proof binds the loopback multicast group and drives a
# real daemon. Concurrent proofs contend for the loopback, and that stalls a
# link renewal past its bound, so the proofs serialize.
discovery = { max-threads = 1 }

[[profile.default.overrides]]
filter = 'test(secret_stores::) | test(teardown::) | test(e2e::) | test(revocation::)'
Expand Down Expand Up @@ -60,3 +64,13 @@ filter = 'package(connetto-file-server) & (test(serve::) | test(sweep::) | test(
test-group = 'docker'
threads-required = 2
slow-timeout = { period = "120s", terminate-after = 5 }

[[profile.default.overrides]]
filter = '''
test(two_nodes_discover_each_other_and_autolink)
| test(a_renewal_re_registers_under_a_new_fingerprint)
| test(a_stopped_discovery_serves_again)
| test(two_clients_discover_each_other_and_autolink)
| test(clients_without_autolink_report_and_link_only_on_the_call)
'''
test-group = 'discovery'
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,10 @@ jobs:
rust-tests:
name: Rust tests ${{ matrix.name }}
runs-on: ubuntu-latest
# The discovery proofs fail here, never skip, when loopback multicast is
# missing (R76 slice 3).
env:
CONNETTO_REQUIRE_MULTICAST: "1"
timeout-minutes: 60
strategy:
fail-fast: false
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ jobs:
coverage:
name: Coverage ${{ matrix.name }}
runs-on: ubuntu-latest
# The discovery proofs fail here, never skip, when loopback multicast is
# missing (R76 slice 3).
env:
CONNETTO_REQUIRE_MULTICAST: "1"
timeout-minutes: 90
# Neither a fork's pull request nor a Dependabot run can read
# CODECOV_TOKEN, so the upload runs for same-repo branches and main only.
Expand Down
68 changes: 61 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions crates/connetto-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,9 @@ ring = { version = "0.17", features = ["std"], optional = true }
# The binary derives the schema version it declares from the translated
# bundle, the same step the server runs. Native only, with the binary.
connetto-schema = { workspace = true, optional = true }
# The peer link the device serves and dials (R76).
connetto-peer = { path = "../connetto-peer", optional = true }
# The peer link the device serves and dials (R76). Its discovery feature is
# on, so a peer build always browses and autolinks what it finds (R76 slice 3).
connetto-peer = { path = "../connetto-peer", optional = true, features = ["discovery"] }
# The page codec, one per target, both selected here rather than by a feature
# because `ReplicaCipher::Encrypted` cannot be honest without it: in a SQLite
# with no codec, `PRAGMA key` is an unrecognised pragma that succeeds silently
Expand Down Expand Up @@ -333,6 +334,9 @@ rcgen = "0.13"
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["tls12"] }
tokio = { version = "1", features = ["test-util"] }
# The loopback multicast probe the discovery proofs run before they trust the
# interface, shared with the peer crate's own proofs.
connetto-peer = { path = "../connetto-peer", features = ["discovery", "test-support"] }

# The fake Secret Service the Linux store tests serve on a peer-to-peer bus.
[target.'cfg(target_os = "linux")'.dev-dependencies]
Expand Down
49 changes: 36 additions & 13 deletions crates/connetto-client/src/builder/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ struct DeviceSetup {
refused: Option<String>,
roots: Vec<Vec<u8>>,
#[cfg(feature = "peer")]
peer_autolink: bool,
#[cfg(feature = "peer")]
peer_listen: SocketAddr,
#[cfg(feature = "peer")]
peer_accepted: Vec<AttestationLevel>,
Expand All @@ -467,6 +469,8 @@ impl Default for DeviceSetup {
refused: None,
roots: Vec::new(),
#[cfg(feature = "peer")]
peer_autolink: true,
#[cfg(feature = "peer")]
peer_listen: SocketAddr::from(([0, 0, 0, 0], 0)),
#[cfg(feature = "peer")]
peer_accepted: AttestationLevel::ALL.to_vec(),
Expand Down Expand Up @@ -578,6 +582,15 @@ where
self
}

/// Whether this device dials the peers discovery finds, on by default
/// (R76 decision 12).
#[cfg(feature = "peer")]
#[must_use]
pub fn with_peer_autolink(mut self, autolink: bool) -> Self {
self.device.peer_autolink = autolink;
self
}

/// The attestation levels this device accepts from its peers, all three
/// by default (R76 decision 8).
#[cfg(feature = "peer")]
Expand Down Expand Up @@ -725,22 +738,32 @@ where
#[cfg(feature = "peer")]
let (peer_events, peer_events_rx) = mpsc::unbounded_channel();
#[cfg(feature = "peer")]
let node = connetto_peer::Node::new(
connetto_peer::Trust {
roots: device.roots.clone(),
accepted: device.peer_accepted,
},
Arc::new(connetto_peer::SystemClock),
peer_events,
)
.map_err(|connetto_peer::TrustError::Root { index, .. }| {
ClientError::InvalidDeploymentRoot { index }
})?;
#[cfg(feature = "peer")]
let (discovery_events, discovery_events_rx) = mpsc::unbounded_channel();
#[cfg(feature = "peer")]
let peer = Peer {
node: connetto_peer::Node::new(
connetto_peer::Trust {
roots: device.roots.clone(),
accepted: device.peer_accepted,
},
Arc::new(connetto_peer::SystemClock),
peer_events,
)
.map_err(
|connetto_peer::TrustError::Root { index, .. }| {
ClientError::InvalidDeploymentRoot { index }
},
)?,
node: node.clone(),
discovery: connetto_peer::Discovery::new(
node,
device.peer_autolink,
discovery_events,
),
listen: device.peer_listen,
events: peer_events_rx,
discovery_events: discovery_events_rx,
#[cfg(all(feature = "peer", target_os = "android"))]
java: device.java.clone(),
};
let (enroller, handle) = Enroller::new(
keys,
Expand Down
Loading
Loading