Request access is not a second pairing ceremony, it is a LAUNCH: an ordinary identified connect with the advertised fingerprint pinned and the handshake budget stretched past the host's approval window. The host parks the connection until somebody approves the device in its console or web UI, then admits the same connection and the stream starts by itself. The desktop shells and the console home have had this for a while (`SpawnOpts::persist_paired`, `screens/pair.rs`); headless callers had no door to it. punktfunk launch <host-ref> --request-access Two behaviours, both small: * `connect_timeout_secs = 185`, matching the host's PENDING_APPROVAL_WAIT. Anything shorter gives up while the approval prompt is still on the operator's screen. * `run_plan` records the host as paired on SessionEvent::Ready. That event IS the approval arriving, and it records the pin the session actually connected WITH rather than re-reading the store — the handshake completed against that identity, which is what makes the record true. Every other launch still records nothing: a plain connect proves reachability, not a new trust decision. Refused under `--exec` (exit 5) rather than silently downgraded. Under --exec the CLI BECOMES the session, so no process survives to observe Ready — a quiet downgrade would leave hosts reading "trusted" forever with nobody able to explain why.
88 lines
3.3 KiB
Rust
88 lines
3.3 KiB
Rust
//! Runs the REAL `punktfunk` binary and pins its self-documentation contract: help goes
|
|
//! to stdout and exits 0, an unknown verb refuses on stderr with the not-found code.
|
|
//!
|
|
//! This exists so CI *executes* the shipped binary at least once per platform. A binary
|
|
//! that compiles but is the wrong program passes every build/clippy/fmt gate — that is
|
|
//! exactly how 0.22.0 shipped a stub as `punktfunk-session` — and only a gate that runs
|
|
//! the thing catches the class. The help paths are the right probe: they touch no config
|
|
//! stores and no network, so they are safe on any runner.
|
|
#![cfg(any(target_os = "linux", windows))]
|
|
|
|
use std::process::Command;
|
|
|
|
fn punktfunk(args: &[&str]) -> std::process::Output {
|
|
Command::new(env!("CARGO_BIN_EXE_punktfunk"))
|
|
.args(args)
|
|
.output()
|
|
.expect("run punktfunk")
|
|
}
|
|
|
|
#[test]
|
|
fn bare_and_help_print_the_overview_on_stdout() {
|
|
for args in [&[][..], &["help"][..], &["--help"][..], &["-h"][..]] {
|
|
let out = punktfunk(args);
|
|
assert!(out.status.success(), "{args:?} must exit 0");
|
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
|
assert!(
|
|
stdout.contains("punktfunk pair"),
|
|
"{args:?} overview lists the verbs"
|
|
);
|
|
assert!(
|
|
stdout.contains("help <command>"),
|
|
"{args:?} overview points at per-verb help"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn per_verb_help_answers_both_spellings() {
|
|
for args in [
|
|
&["help", "launch"][..],
|
|
&["launch", "--help"][..],
|
|
&["launch", "-h"][..],
|
|
] {
|
|
let out = punktfunk(args);
|
|
assert!(out.status.success(), "{args:?} must exit 0");
|
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
|
assert!(
|
|
stdout.contains("--exec"),
|
|
"{args:?} documents launch's flags"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn version_prints_the_crate_version() {
|
|
let out = punktfunk(&["--version"]);
|
|
assert!(out.status.success());
|
|
assert!(String::from_utf8_lossy(&out.stdout).contains(env!("CARGO_PKG_VERSION")));
|
|
}
|
|
|
|
#[test]
|
|
fn unknown_verbs_refuse_with_the_not_found_code() {
|
|
let out = punktfunk(&["frobnicate"]);
|
|
assert_eq!(out.status.code(), Some(5), "unknown verb exits 5");
|
|
assert!(String::from_utf8_lossy(&out.stderr).contains("unknown command"));
|
|
|
|
let out = punktfunk(&["help", "frobnicate"]);
|
|
assert_eq!(out.status.code(), Some(5), "unknown help topic exits 5");
|
|
}
|
|
|
|
/// `discover` and `launch --request-access` document themselves. Help only — the verbs
|
|
/// themselves browse the LAN and dial a host, which no runner may be asked to do.
|
|
///
|
|
/// The Decky panel detects a too-old client by exactly the signature the test above pins
|
|
/// (exit 5 + `unknown command`), so this is the other half of that contract: on a client new
|
|
/// enough, `discover` is a verb with help rather than an unknown word.
|
|
#[test]
|
|
fn the_request_access_surfaces_document_themselves() {
|
|
let out = punktfunk(&["help", "discover"]);
|
|
assert!(out.status.success(), "discover has its own help topic");
|
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
|
assert!(stdout.contains("--timeout"), "discover documents --timeout");
|
|
assert!(stdout.contains("--json"), "discover documents --json");
|
|
|
|
let out = punktfunk(&["launch", "--help"]);
|
|
assert!(String::from_utf8_lossy(&out.stdout).contains("--request-access"));
|
|
}
|