Finish the devices crate, and stop it being invisible
crates/lumbridge-devices was in neither workspace.members nor workspace.exclude, which is not a build error: Cargo simply never looked at it. Its 19 tests had never run, it never inherited unsafe_code = "forbid" or pedantic Clippy, and `cargo check` inside it refused outright with "current package believes it's in a workspace when it's not". Under that cover its lib.rs had been declaring `mod manage;` and re-exporting five items from a manage.rs that did not exist, so the crate did not compile at all. manage.rs is written here to the contract lib.rs already specified. available_actions reads neither DeviceReachability nor Device::presence: an offline device keeps its workspace action and an online one does not gain one, because the registry is the axis and reachability is Tailscale's separate claim. DeviceAction has three variants and no more -- install, reboot and upgrade are absent from the type rather than rejected at runtime, since a variant that exists is eventually rendered as a greyed-out button reading "coming soon" instead of "impossible". A test walks every operation in the module over every fixture device and asserts none of them ever produces LumbridgePresence::Confirmed, which stays unproducible until a lumbridge-remote runtime can answer for itself. RemoteTransport had been declared twice, here and in lumbridge-core, with byte-identical storage strings, because this crate had no dependency on that one. Two enumerations of one choice persisted through the same strings is a drift waiting to happen, so core keeps the single definition -- gaining the default and the picker phrase -- and this crate depends on core and re-exports it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPYebLiN2w4TqnHUYGdECq
This commit is contained in:
co-authored by
Claude Opus 5
parent
73df4fa679
commit
7bee985279
@@ -17,12 +17,29 @@ pub use workspace::{
|
||||
};
|
||||
|
||||
/// The transport Lumbridge uses to reach a user-owned remote machine.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
///
|
||||
/// This is the one definition. A second copy briefly existed in
|
||||
/// `lumbridge-devices` while that crate had no dependency on this one, and two
|
||||
/// enumerations of the same choice, persisted through the same strings, is a
|
||||
/// drift waiting to happen: a registration made on the devices page and a
|
||||
/// `RemoteHost` row written by `lumbridge-storage` describe the same decision
|
||||
/// and must survive the same round trip.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum RemoteTransport {
|
||||
/// The system OpenSSH client, including the user's SSH config, `ProxyJump`,
|
||||
/// agent, and a Tailscale `MagicDNS` name or tailnet IP when supplied.
|
||||
///
|
||||
/// The default, and `docs/ARCHITECTURE.md` says why: it honours setup the
|
||||
/// user already has, and costs them nothing new.
|
||||
#[default]
|
||||
OpenSsh,
|
||||
/// The Tailscale CLI's SSH proxy and host-key verification path.
|
||||
///
|
||||
/// An explicit alternative rather than a fallback. It is right for a user
|
||||
/// governed by tailnet ACLs who wants no SSH key in the loop, and wrong for
|
||||
/// one whose `ProxyJump` or per-host identity lives in their SSH config,
|
||||
/// because `tailscale ssh` never reads that file. Only the user knows
|
||||
/// which they are, so nothing here guesses.
|
||||
TailscaleSsh,
|
||||
}
|
||||
|
||||
@@ -35,6 +52,13 @@ impl RemoteTransport {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a persisted transport back, or reports that it is not one we know.
|
||||
///
|
||||
/// Returns `None` rather than falling back to [`Self::OpenSsh`] for an
|
||||
/// unrecognised string: a value written by a later version means the note
|
||||
/// was made by software that knew something this one does not, and quietly
|
||||
/// re-pointing it at OpenSSH would change how a machine is contacted
|
||||
/// without telling anybody.
|
||||
#[must_use]
|
||||
pub fn from_storage_name(value: &str) -> Option<Self> {
|
||||
match value {
|
||||
@@ -43,6 +67,15 @@ impl RemoteTransport {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The phrase for a picker, naming the client rather than our opinion of it.
|
||||
#[must_use]
|
||||
pub const fn describe(self) -> &'static str {
|
||||
match self {
|
||||
Self::OpenSsh => "OpenSSH, using your SSH config",
|
||||
Self::TailscaleSsh => "Tailscale SSH",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A connection profile. It contains routing metadata, never credentials.
|
||||
|
||||
Reference in New Issue
Block a user