From 0c9d8533da21d71ae6903455f85e372df61b3705 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Sep 2026 15:59:03 -0700 Subject: [PATCH] Remove various caveats from the readme and code The core cryptography has had an external review, and the functionality we have is far enough along that we can remove the big red warning and scary environment variable. We do still list plenty of caveats, which boil down to: this is still early days for tailscale-rs, so expect more bugs and missing features than maybe you'd like. We also log a warning to that effect when the library is first used, which we'll remove at some point in the future once we feel ready to promise more. Signed-off-by: David Anderson Change-Id: I7c23eee1dbb2fd1d28a55fab094848926a6a6964 --- CHANGELOG.md | 3 +++ README.md | 46 ++++++++++++-------------------- examples/README.md | 3 --- examples/axum/README.md | 2 +- examples/peer_ping/README.md | 2 +- examples/tcp_echo/README.md | 2 +- src/error.rs | 8 ------ src/lib.rs | 29 +++----------------- tests/basic.rs | 2 -- ts_python/README.md | 2 +- ts_python/examples/README.md | 3 --- ts_python/examples/udp/README.md | 4 +-- ts_python/examples/udp/recv.py | 2 +- ts_python/examples/udp/send.py | 2 +- ts_tunnel/README.md | 4 +-- 15 files changed, 33 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00266f93..ab136a14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ Record breaking or significant changes here. All dates are UTC. Put changes for the upcoming release here! +- Changed (Rust API, lang bindings): the `TS_RS_EXPERIMENT` environment variable is no longer required to use the + library. The library logs a warning during initialization, as a reminder that it's still work-in-progress software. + ## [0.5.0](https://github.com/tailscale/tailscale-rs/releases/tag/v0.5.0) - 2026-08-14 - **Breaking** (Rust API, lang bindings, ts_control): Support for `ephemeral` diff --git a/README.md b/README.md index 155b7494..89e6301f 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,8 @@ https://tailscale.com `tailscale-rs` is a work-in-progress Tailscale library written in Rust, with language bindings to C, Elixir, and Python. -> [!CAUTION] -> This software is unstable and insecure. -> -> We welcome enthusiasm and interest, but please **do not** build production software using these -> libraries or rely on it for data privacy until we have a chance to batten down some hatches -> and complete a third-party audit. -> -> See [Caveats](#caveats) for more details. +> [!NOTE] +> This software is under active development. See [Caveats](#caveats) for more details. ## Getting Started @@ -72,32 +66,28 @@ async fn main() -> Result<(), Box> { This software is still a work-in-progress! We are providing it in the open at this stage out of a belief in open-source and to see where the community runs with it, but please be aware of a few important considerations: -- This implementation contains unaudited cryptography and hasn't undergone a comprehensive security analysis. - Conservatively, assume there could be a critical security hole meaning anything you send or receive could be in the - clear on the public Internet. -- There are no compatibility guarantees at the moment. This is early-days software — we may break dependent code - in order to get things right. -- We currently rely on DERP relays for all communication. Direct connections via NAT holepunching will be a seamless - upgrade in the future, but for now, this puts a cap on data throughput. -- The `TS_RS_EXPERIMENT` environment variable is required to be set to `this_is_unstable_software` - for all code linked against `tailscale-rs`; this includes Rust, C, Elixir, and Python code. We'll remove this - requirement after a third-party code/cryptography audit and any necessary fixes. +- There are no compatibility guarantees at the moment. We may break dependent code in order to get things right, + although we will try to avoid doing so gratuitously. +- Direct connections via NAT traversal is a work in progress. Communication may fall back to DERP relaying in more cases, + with a corresponding hit to latency and throughput. +- Core networking functionality is implemented. Many other features are still either in progress or not implemented yet. + See [Status](#status) for details. -## Versioning, Releases, and Compatability +We encourage you to experiment with this library and build things with it, as long as you're okay with these caveats. -We follow semver and aim to make a point release roughly monthly. Since we are pre-1.0, we make no -backwards-compatability guarantees. We are aiming to have a stable 1.0 release as soon as we can, but we currently don't -have a timeline. +## Versioning, Releases, and Compatibility + +We follow semver and aim to make a point release roughly monthly. Since we are pre-1.0, we make no strong +backwards-compatibility guarantees. ## MSRV and Edition The current MSRV is 1.94.1. The current edition is Rust 2024. `tailscale-rs` has a rolling MSRV (Minimum Supported Rust Version) policy to support the current and previous Rust -compiler versions, and the latest -[edition of Rust](https://doc.rust-lang.org/edition-guide/editions/index.html). +compiler versions, and the latest [edition of Rust](https://doc.rust-lang.org/edition-guide/editions/index.html). -We may lag the latest version/edition in rare cases for our dependencies to catch up and for us to perform any necessary +We may periodically lag the MSRV behind this latest version/edition in rare cases for our dependencies to catch up and for us to perform any necessary fixes. ## Platform Support @@ -110,9 +100,8 @@ We support the following platforms and architectures: ## Status -`tailscale-rs` is a work-in-progress - we're still rapidly iterating, fixing bugs, and adding new features. We aim to -keep this section up-to-date, but our [issue tracker](https://github.com/tailscale/tailscale-rs/issues) -is the best way to see the latest updates. +`tailscale-rs` is a work-in-progress. We're still rapidly iterating, fixing bugs, and adding new features. +We aim to keep this section up-to-date, but our [issue tracker](https://github.com/tailscale/tailscale-rs/issues) is the best way to see the latest updates. ### Implemented @@ -133,7 +122,6 @@ timeline or completion: - Direct connections (NAT traversal, STUN, and Disco) - Peer lookups (addressing peers by hostname) -- Third-party code and cryptography audit ### Unsupported diff --git a/examples/README.md b/examples/README.md index d7ad5c33..2c50cabe 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,9 +14,6 @@ tailnet, referred to as `$AUTH_KEY` below examples take care of that for you - A tailnet policy configured to allow access between your local machine and the example code -Also note the `TS_RS_EXPERIMENT=this_is_unstable_software` environment variable in all the examples -below; for an explanation, see [the Caveats section of the README](../README.md#caveats). - ## Overview Brief descriptions and links to each example. diff --git a/examples/axum/README.md b/examples/axum/README.md index 3b0c9a5e..fbad138b 100644 --- a/examples/axum/README.md +++ b/examples/axum/README.md @@ -7,7 +7,7 @@ An `axum`-based HTTP server that serves a simple webpage over the tailnet. This `tailscale-rs` to be compiled with the `axum` feature: ```sh -$ TS_RS_EXPERIMENT=this_is_unstable_software cargo run --example axum --features axum -- --auth-key $AUTH_KEY --key-file tsrs_keys.json +$ cargo run --example axum --features axum -- --auth-key $AUTH_KEY --key-file tsrs_keys.json ... INFO axum: http server listening url=http://:80/index.html ``` diff --git a/examples/peer_ping/README.md b/examples/peer_ping/README.md index 8ff37f2a..454735f8 100644 --- a/examples/peer_ping/README.md +++ b/examples/peer_ping/README.md @@ -23,7 +23,7 @@ Then, in another terminal, run the example: ```sh # Terminal 2 -$ TS_RS_EXPERIMENT=this_is_unstable_software cargo run --example peer_ping -- --auth-key $AUTH_KEY --key-file tsrs_keys.json --peer :5678 +$ cargo run --example peer_ping -- --auth-key $AUTH_KEY --key-file tsrs_keys.json --peer :5678 ... INFO ts_runtime::multiderp: new home derp region selected region_id=1 latency_ms=12.223305702209473 ... diff --git a/examples/tcp_echo/README.md b/examples/tcp_echo/README.md index 38d5bec8..fa485083 100644 --- a/examples/tcp_echo/README.md +++ b/examples/tcp_echo/README.md @@ -9,7 +9,7 @@ For this example, you can use netcat (`nc`) to test the server. First, start the ```sh # Terminal 1 -$ TS_RS_EXPERIMENT=this_is_unstable_software cargo run --example tcp_echo -- --auth-key $AUTH_KEY --key-file tsrs_keys.json +$ cargo run --example tcp_echo -- --auth-key $AUTH_KEY --key-file tsrs_keys.json ... INFO tcp_echo: listening_addr=:1234 ... diff --git a/src/error.rs b/src/error.rs index e8cd261c..9c781ad6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -25,14 +25,6 @@ pub enum Error { #[error("an error writing out the key file")] KeyFileWrite, - /// The environment variable `TS_RS_EXPERIMENT` was not set. - /// - /// The end-user must set `TS_RS_EXPERIMENT=this_is_unstable_software` to acknowledge that tailscale-rs - /// is early-days experimental software containing bugs, unvalidated cryptography, and no stability - /// or compatibility guarantees. - #[error("the environment variable `{}` was not set", crate::ENV_MAGIC_VAR)] - UnstableEnvVar, - /// An error occurred which can not be anticipated or handled by a library user. /// /// This is likely due to a bug in our code or a rare and unexpected error. diff --git a/src/lib.rs b/src/lib.rs index e9e29185..b4cc7f3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,10 +57,6 @@ //! //! ## Using `tailscale` //! -//! To use this crate or the language bindings, you will need to set the `TS_RS_EXPERIMENT` env var -//! to `this_is_unstable_software`. We'll remove this requirement after a third-party code/cryptography -//! audit and any necessary fixes. -//! //! Under the hood, we use Tokio for our async runtime. You must also use Tokio, any kind and most //! configurations of Tokio runtimes should work, but there must be one available when you call any //! async API functions. The easiest way to do this is to use `#[tokio::main]`, see the @@ -189,7 +185,9 @@ impl Device { /// # Ok(()) } /// ``` pub async fn new(config: &Config, auth_key: Option) -> Result { - check_magic_env()?; + tracing::warn!( + "tailscale-rs is early software in active development, expect more bugs and missing features than usual." + ); let keys = (&config.key_state).into(); let rt = ts_runtime::Runtime::spawn(ts_runtime::Config { @@ -376,24 +374,3 @@ pub mod keys { NodeKeyPair, NodePrivateKey, NodePublicKey, NodeState, PersistState, }; } - -const ENV_MAGIC_VAR: &str = "TS_RS_EXPERIMENT"; -const ENV_MAGIC_VALUE: &str = "this_is_unstable_software"; - -fn check_magic_env() -> Result<(), Error> { - if std::env::var(ENV_MAGIC_VAR).as_deref() != Ok(ENV_MAGIC_VALUE) { - let warning = format!( - " -check failed: set {ENV_MAGIC_VAR}={ENV_MAGIC_VALUE} to acknowledge that tailscale-rs is early-days -experimental software containing bugs, unvalidated cryptography, and no stability or compatibility -guarantees. - " - ); - - eprintln!("{}", warning.trim()); - - return Err(Error::UnstableEnvVar); - }; - - Ok(()) -} diff --git a/tests/basic.rs b/tests/basic.rs index 5d593763..b04ed5ac 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -197,7 +197,5 @@ async fn test_udp_unidir(tx: &UdpSocket, rx: &UdpSocket) { } async fn make_ts_device() -> Result { - unsafe { std::env::set_var("TS_RS_EXPERIMENT", "this_is_unstable_software") }; - Device::new(&Config::default(), Some(ts_test_util::auth_key().unwrap())).await } diff --git a/ts_python/README.md b/ts_python/README.md index 9a9f5e72..1cef1296 100644 --- a/ts_python/README.md +++ b/ts_python/README.md @@ -36,7 +36,7 @@ if __name__ == "__main__": To run this demo: ```console -$ TS_RS_EXPERIMENT=this_is_unstable_software python demo.py +$ python demo.py ``` ## Building and Usage diff --git a/ts_python/examples/README.md b/ts_python/examples/README.md index 650c0cfa..7f2698b9 100644 --- a/ts_python/examples/README.md +++ b/ts_python/examples/README.md @@ -16,9 +16,6 @@ For all the examples, you'll need: - A tailnet policy configured to allow access between your local machine and the example code, and between the examples themselves -Also note the `TS_RS_EXPERIMENT=this_is_unstable_software` environment variable is required for all -the examples below; for an explanation, see [the Caveats section of the README](../../README.md#caveats). - ## [UDP](udp) A UDP sender and receiver. The sender sends UDP datagrams to the receiver over the tailnet. \ No newline at end of file diff --git a/ts_python/examples/udp/README.md b/ts_python/examples/udp/README.md index 9685d5ae..0bd78127 100644 --- a/ts_python/examples/udp/README.md +++ b/ts_python/examples/udp/README.md @@ -10,7 +10,7 @@ First, start the receiver: ```sh # Terminal 1 -$ TS_RS_EXPERIMENT=this_is_unstable_software ./recv.py $AUTH_KEY_1 5678 +$ ./recv.py $AUTH_KEY_1 5678 ... [:5678] udp bound, local endpoint: ('', 5678) ... @@ -20,7 +20,7 @@ Then, in another terminal, start the sender: ```sh # Terminal 2 -$ TS_RS_EXPERIMENT=this_is_unstable_software ./send.py $AUTH_KEY_2 5678 +$ ./send.py $AUTH_KEY_2 5678 ... [:1234] udp bound, local endpoint: ('', 1234) [:1234->:5678|0001] sent message: b'HELLO' diff --git a/ts_python/examples/udp/recv.py b/ts_python/examples/udp/recv.py index 7b15ba62..53da8c4a 100755 --- a/ts_python/examples/udp/recv.py +++ b/ts_python/examples/udp/recv.py @@ -33,7 +33,7 @@ async def main(auth_key: str, bind_port: int) -> None: if __name__ == "__main__": parser = argparse.ArgumentParser( description="UDP receiver built with `tailscale-py`", - usage="TS_RS_EXPERIMENT=this_is_unstable_software %(prog)s [options]", + usage="%(prog)s [options]", ) parser.add_argument("auth_key", help="auth key to register with tailnet") parser.add_argument("bind_port", help="local UDP port to bind", type=int) diff --git a/ts_python/examples/udp/send.py b/ts_python/examples/udp/send.py index 58810d6d..150eeb52 100755 --- a/ts_python/examples/udp/send.py +++ b/ts_python/examples/udp/send.py @@ -36,7 +36,7 @@ async def main(auth_key: str, peer_ip: str, peer_port: int) -> None: if __name__ == "__main__": parser = argparse.ArgumentParser( description="UDP sender built with `tailscale-py`", - usage="TS_RS_EXPERIMENT=this_is_unstable_software %(prog)s [options]", + usage="%(prog)s [options]", ) parser.add_argument("auth_key", help="auth key to register with tailnet") parser.add_argument("peer_ip", help="peer's tailnet IP address") diff --git a/ts_tunnel/README.md b/ts_tunnel/README.md index 948dbe1d..790cc220 100644 --- a/ts_tunnel/README.md +++ b/ts_tunnel/README.md @@ -21,8 +21,8 @@ tests). ## Security limitations -This crate has not yet been subjected to a code audit by expert cryptography engineers. Conservatively, assume that -there could be a critical security hole that exposes your traffic to attackers. +The code in this crate has been reviewed by third-party security experts. However, it's still relatively young code +that's still being worked on, so depending on your comfort level you may want to conduct your own evaluation. As stated above, this crate by itself is NOT a complete implementation of WireGuard, and should not be used as one.