Skip to content

podssh v1.0.0-beta.4

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 02 Nov 01:59
· 729 commits to main since this release

podssh v1.0.0-beta.4

The fourth beta. It carries the repairs since v1.0.0-beta.3: a run in the
background that podssh starts again and watches, and that leaves a login
session's scope of systemd, a node that goes on past its pair's expiry, a
quick tunnel that races its roads, keeps two connections and rides out the
edge's GOAWAY, and the repairs of a bulk session through a node. A beta is a prerelease. Its tag never moves: a defect found in it
goes into the next beta.

The files

File For
podssh-x86_64-unknown-linux-musl Linux on x86-64, static: no library and no loader needed
podssh-aarch64-unknown-linux-musl Linux on aarch64, static
podssh-armv7-unknown-linux-musleabihf Linux on 32-bit ARM with hard float (a Raspberry Pi with a 32-bit system), static
podssh-riscv64gc-unknown-linux-musl Linux on 64-bit RISC-V, static
podssh-aarch64-apple-darwin macOS on Apple silicon; it links the system's libraries only
podssh-x86_64-apple-darwin macOS on Intel
podssh-x86_64-pc-windows-msvc.exe Windows on x86-64, with a static C runtime
podssh-aarch64-pc-windows-msvc.exe Windows on ARM64, with a static C runtime
SHA256SUMS The SHA-256 of each binary
SHA256SUMS.sigstore.json The signature of SHA256SUMS: Sigstore's keyless signing, by the release workflow at this tag
provenance.sigstore.json The provenance of each binary (SLSA), signed the same way: the workflow, the tag and its commit
THIRD-PARTY-LICENSES.md The licenses of the crates in the binaries, with their texts

Each binary ran on its own platform before it was published: --version,
the whole manual, keygen and keygen -y, the iroh road's parse of a
ticket, WARP's road asking for Cloudflare's Terms before it dials, and
GitHub's SSH banner through the live relay.

Check a download

T=v1.0.0-beta.4; B=podssh-x86_64-unknown-linux-musl   # or another file of the table
curl -fsSLO "https://github.com/Azathothas/podssh/releases/download/$T/$B"
curl -fsSLO "https://github.com/Azathothas/podssh/releases/download/$T/SHA256SUMS"
grep " $B\$" SHA256SUMS | sha256sum -c - && chmod +x "$B"
./"$B" --version   # podssh 1.0.0-beta.4 (the commit of the tag)
./"$B" doctor      # what this host allows, and whether the whole path works

On macOS, check with shasum -a 256 -c in place of sha256sum -c -. A
binary that curl fetched has no quarantine; after a browser's download,
run xattr -d com.apple.quarantine "$B" first. On Windows, compare
(Get-FileHash podssh-x86_64-pc-windows-msvc.exe).Hash with its line in
SHA256SUMS (the case of the letters differs).

The provenance of a binary names the release workflow and the tag (with the
GitHub CLI):

gh attestation verify "$B" --repo Azathothas/podssh \
  --signer-workflow Azathothas/podssh/.github/workflows/release.yml --source-ref "refs/tags/$T"

The signature of SHA256SUMS names the workflow at the tag (with cosign; 3.x
and 2.6 both check it):

curl -fsSLO "https://github.com/Azathothas/podssh/releases/download/$T/SHA256SUMS.sigstore.json"
cosign verify-blob --bundle SHA256SUMS.sigstore.json \
  --certificate-identity "https://github.com/Azathothas/podssh/.github/workflows/release.yml@refs/tags/$T" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com SHA256SUMS

The two proofs and podssh --version name the same commit.

The sizes

The sizes of the release's dry run of 2026-11-01 (at 1bafa9d, the code of
this tag, run 41337605530), beside beta.3's:

Binary beta.3 beta.4
Linux x86-64 15.2 MiB 15.7 MiB
Linux aarch64 11.7 MiB 12.1 MiB
Linux armv7 8.8 MiB 9.1 MiB
Linux riscv64 11.7 MiB 12.1 MiB
macOS, Apple silicon 9.2 MiB 9.5 MiB
macOS, Intel 12.2 MiB 12.6 MiB
Windows x86-64 11.9 MiB 12.3 MiB
Windows ARM64 10.5 MiB 10.8 MiB

What works

podssh ssh, each, run, job, session, containers, proxy, pipe,
cp, mv, scp, sftp and edit, doctor, keygen, agent, man,
status, ping, health, node, operator, relay, chat, play,
config, mcp, update and detached. podssh man is the reference: each command,
flag, -o keyword, variable, file and exit code. The iroh road is in each
binary: podssh node --iroh, a destination iroh:TICKET, and
--iroh-ticket. So is WARP's road, warp://HOST[:PORT], and the DERP road,
podssh node --derp and a destination derp:TICKET. These binaries have no
Tailscale: podssh ts exits with 70 and says so.

What to test again

New since v1.0.0-beta.3:

  • --detach (-f for ssh): a run that podssh sends into the background
    itself, once it is online, with its log in the cache (T-380); with
    --restart, a small supervisor starts it again whenever it ends, never
    giving up, and starts it again when it hangs: each run beats a file each
    10 s, and one silent for 90 s is ended and started again (T-390, T-394).
    --detach-name NAME and podssh detached list, status NAME and stop NAME: a second start of a name that runs is refused (T-392). A run with no
    /dev/null uses closed pipes, the log is cut with no line lost, old files
    go, and the run leaves the caller's working directory (T-397). A line that
    fails to write (a full disk, a closed journal) no longer ends a run (T-389).
    On Linux, a run detached from a login session asks the user's systemd for
    a scope of its own, podssh-detached-PID.scope, as tmux does, so that a
    logout does not end it where logind ends a session's processes; its log
    says the outcome, and PODSSH_SYSTEMD=no asks nothing (T-381).
  • podssh ssh --persist-forever: connect again after each loss with no limit
    (T-391); podssh ssh --install NAME -N -R ... --persist: a reverse tunnel as
    a service of this user (T-393). --install services restart after each end,
    with a cron watchdog, a LaunchAgent on macOS and a task on Windows (T-393).
  • podssh update runs the new binary once before it takes the old one's
    place, keeps the old one as podssh.prev, and --rollback puts it back
    (T-396).
  • A node says its pair's expiry 24 h, 6 h and 1 h before it, with the command
    that makes the next pair; podssh relay pair NAME makes it in the last day
    of the old one, and the node takes it at the expiry with no new start;
    podssh status names each stored pair's expiry (T-395). A node closed by
    the relay for a fault connects again (T-409), and a bulk session through a
    node moves with no fault (T-410). A node that starts while the relay still
    holds the socket of the pair's last node (a restart, a script that starts
    the next one at once) connects again for 30 s instead of exiting at the
    relay's 409 (T-416).
  • The quick tunnel (podssh node --quick-tunnel): its roads (QUIC, HTTP/2,
    HTTP/2 inside WARP) race with a stagger of 2 s, QUIC after a probe of UDP of
    300 ms (T-400); on the edge's GOAWAY its visitors go on for up to 90 s while
    a new connection takes the new ones (T-402); a window of small frames left
    unread no longer ends the connection (T-408); a push of configuration is
    answered over HTTP/2 and QUIC (T-404, T-411); a refusal of
    api.trycloudflare.com for now is asked again after its Retry-After (T-401).
    The node keeps two connections to the edge, the second to its other region,
    so that a region in trouble leaves one standing (T-414).
  • WARP's tunnel under volume (T-398), and a front door's new key read from the
    device's record (T-399); a front door that shows another certificate once
    is asked once more a second later before the road gives up (T-419).
  • pipe and proxy write what their source has ready together, up to
    32 KiB, so that a source of small reads no longer pays a write for each.
    Through Tor (a build with the feature tor) that took the download from
    2.9 to 7.8 MiB/s through a private network; the Tor road also runs on two
    threads, and it is measured on Tor's public network (T-353).
  • DNS over HTTPS through a proxy asks each resolver by its name first (T-405),
    and over HTTP/2 it ends each connection with GOAWAY (T-418).
  • ssh+tls://, SSH inside TLS as a hop or the destination (#61, T-372); a
    Shadowsocks road from a file of ss:// lines that a subscription can
    refresh (#62, T-373); meek and WebTunnel inside the Tor road's process, in a
    build with the feature tor (T-385).
  • cp of many small files: the far digest's command starts beside each
    file's sync and close, and a tree of 50 files or more that go one at a
    time says once that --parallel 8 copies 8 at once (T-417).

What a beta does not have yet

  • The whole check of a release from end to end with no human
    (scripts/release-check.sh, T-251): its parts ran on this beta's way; the
    whole run, before the tag and after it, is v1.0.0's.
  • Signatures of the platforms: the Mac binaries are not signed with an
    Apple Developer ID, and the Windows binaries carry no Authenticode
    signature, so SmartScreen may warn. The proofs above stand in for them.

Report a defect

Open an issue at https://github.com/Azathothas/podssh/issues with the
output of podssh --version and podssh doctor --json. Read that output
before you post it: it names this host's proxy and addresses, and never a
token or a password.

The licenses of the crates in the binaries, with their texts: THIRD-PARTY-LICENSES.md.

The commits of this release

Build and CI

  • CI: the Windows test of --restart gives --keep-listening; T-410's live move from GitHub's network (e837c63)

Other

  • T-370, partial: the public forwarders of #59 by a word, and a fallback to them (the draft of 2026-10-31 merged) (5fa6f81)
  • T-370: done. The public forwarders' live run passed; GitHub #60 and #72 closed (a706d0e)
  • Repair the gate at 5fa6f81: the manual's check read transport.rs to a test-only import (52006dd)
  • v1.0.0-beta.3 is published and proven (T-309) (546e706)
  • T-353, partial: the Tor road through Arti, tor://, in the feature crate podssh-tor (0cab0df)
  • T-380 and T-381: --detach, after a study of what ends a background process (67b439f)
  • T-380: done. --detach and -f: a run sent into the background by podssh itself (adb0cfe)
  • T-382: done (Unix). podssh session start asks its prompts on the terminal, then leaves it (b3eaf73)
  • T-372: done. ssh+tls://, SSH inside TLS as a hop or the destination (GitHub #61) (60c2414)
  • T-383: partial. --detach and session start on Windows: out of the caller's job, the console kept until ready (cd56f64)
  • T-353: the documents of the Tor road: tor:// in docs/cli.md, its state in carriers.md, WARP's and Tor's rows in the road table (04cf216)
  • T-353: the Tor road against a Tor network of C tor, with chutney: through a stand-in proxy, a login through an exit (76ead32)
  • T-383: --detach on Windows: the child closes the caller's handles at ready (ec2252b)
  • T-353: doctor --full bootstraps Tor in a build with the feature: the line tor (35e4797)
  • T-383: done. --detach and session start measured on Windows and macOS in Actions (d03048d)
  • T-373: done. A Shadowsocks road from a file of ss:// lines that a subscription can refresh (GitHub #62) (8ff4b0a)
  • T-334: partial. A headscale stand-in for the live runs of podssh ts, and three repairs it found (15c83ba)
  • T-385: meek and WebTunnel inside the Tor road's process, filed from a study; T-353 waits for Q60 (68142cc)
  • T-334: done. The headscale stand-in's 14 runs passed in Actions, the live relay's three among them (530c445)
  • T-384: done. No panic of kameo when the control server refuses a node: the fork's patch 0029 (6d90d6a)
  • T-386: partial. Dependabot's minor and patch group (GitHub #79) in the lock, and the five pull requests of 2026-11-01 filed (cfa2a64)
  • T-386: done. Dependabot's rand 0.10, sha2 0.11 and hmac 0.13 together, and Tailscale 1.104.4 for the stand-in tailnet (GitHub #78, #80 to #82) (8368d54)
  • T-251: partial. The planted defects of the checks as files, a runner, and a workflow that runs them (e36aee6)
  • T-251: plant-each.sh passes shellcheck: empty assignments quoted, the trap's function marked (279e9f0)
  • T-251: the record names the drafts being written: four drafts of plants, beside T-385's (9390683)
  • T-251: the live tests of a node run the layer on the binary's stack; relay-live.yml runs node_live (a17c398)
  • box.yml: the box like the target sandbox and the chat between boxes, by hand (T-251) (ed4c7f3)
  • podssh-todo's test of the GitHub map: its plant takes #77 out of the line of pull requests whatever its words (deb6463)
  • T-385: done. meek and WebTunnel inside the Tor road's process, measured against Tor's own servers in a private network (725d66d)
  • T-251: the live runs of 2026-11-01: a node idle 10 minutes passes; IRC through the relay (654d888)
  • T-387: partial. The layer reads its link while the application is slow; acknowledgements cover the bytes written (dd65d12)
  • T-388, T-387: done. A move through a node keeps the node's socket; 18 entries from the studies of d-mon and cfrs (ea2bd4f)
  • T-389, T-391: done. A line that fails to write no longer ends podssh; --persist-forever never gives up (b29fd97)
  • T-390: done. --detach --restart: a supervisor starts the detached run again whenever it ends (4cddf05)
  • T-401, T-407: done. The quick tunnel's request asked again after 429 or 5xx; a peer's text and header made one line (eba2358)
  • T-398: done. WARP's tunnel reads while a packet waits, and takes small frames up to its whole window (66044bd)
  • T-409: done. A node that the relay closes for a fault connects again; T-410 filed (ce72ad4)
  • T-390: the supervisor keeps its own standard handles out of the run on Windows (f3ceca1)
  • T-393: done. --install always restarts: no start limit, a cron watchdog, a LaunchAgent; ssh --install (3756aae)
  • T-396: done. podssh update tries the new binary first and keeps the one before; --rollback (884052f)
  • T-399: done; T-410: partial. WARP reads a front door's new key from the device's record; a node's control goes before its bytes (c54b7b4)
  • T-410: done. Only the far end ends a retired link; a move through a node meets no fault (0c4bc78)
  • T-403: done. The Cap'n Proto reader makes a list's elements as they are read; fuzz targets for the quick tunnel's parsers (9b72e7d)
  • T-404: done. The quick tunnel answers a push of configuration as cloudflared does; T-411 filed (35b593d)
  • T-405: done. Through a proxy, DNS over HTTPS asks each resolver by its name first (87645d1)
  • T-406: done. The edge's facts that cfrs's testers measured, in the design as a third party's (a09f40e)
  • T-395: done. A node says its pair's expiry before it, and goes on with the next pair (abf1322)
  • T-412: done. The stand-in relay closes a node for a frame of a forgotten session, as the live relay does (24198e4)
  • T-392: done. A lock for each detached run, with podssh detached list, status and stop (7894152)
  • T-394: done. A heartbeat of each run of --restart, which its supervisor watches (a8e653a)
  • T-397: done. --detach's smaller gaps: no /dev/null, a cut of the log that loses no line, old files, the working directory (520960d)
  • T-413: done. The test of DoH over HTTP/2 no longer races two equal bounds (1e5863f)
  • T-400: done. The quick tunnel's roads raced with a stagger, and a probe of UDP before QUIC (c40ac06)
  • T-402: done. On the edge's GOAWAY the quick tunnel drains its connection while the next one registers (62264ec)
  • T-408: done. The quick tunnel's server holds its whole window in small frames (18bab22)
  • T-411: done. The quick tunnel over QUIC answers a push of configuration as over HTTP/2 (da543fd)
  • quick-tunnel-live: doctor's no answer of UDP may be the send's own error (dd4fb65)
  • T-400's live run: HTTP/2 in 0.4 s with UDP dropped, WARP's tunnel in 4.5 s with TCP too (6fea7db)
  • T-400's live record: the race to HTTP/2 took 0.3 s, not 0.4 s (c1194df)
  • T-416: a node that meets 409 at its first registration connects again for 30 s (6a13686)
  • T-251: the throughput run's forward cell through the relay's own loop; many small files; the left UNVERIFIEDs filled (44e4e00)
  • T-251, T-415: the planted defects of each deferred check, the box on GitHub's runner, and the release check (fff2252)
  • T-251: the interop baseline names the part interop-ptyrun.sh; interop.sh prints the driver's line (4820e0e)
  • T-417: the far digest's command starts beside the sync and the close; a big tree one at a time names --parallel (d98cd36)
  • T-251: the headscale row here: 11 passed, the live relay's 3 left to Actions (exit 3) (9e3a3b8)
  • The fourth beta made ready, v1.0.0-beta.4 (the steps of T-309) (0872994)
  • The notes of v1.0.0-beta.4: the sizes of the dry run (T-309) (7855981)
  • The operator's rulings of 2026-11-01: Q60, Q61, Q62, and v1.0.0 unattended (0e1866b)
  • T-414: the quick tunnel's node keeps two connections to the edge (Q62) (e681aaf)
  • T-381: a detached run asks the user's systemd for a scope of its own (Q61) (afbd10d)
  • T-353: the Tor road's live test on Tor's public network (Q60) (f40298c)
  • T-418 (partial): the test of DoH over HTTP/2 no longer spins on h2's repeated error, and the client ends its connection with GOAWAY (5ae713a)
  • T-414: done, two connections of the quick tunnel live on Cloudflare's edge; T-419: WARP's road tries the record's key once more when the API gives it again (d3353a1)
  • T-418: done, doh-live passed at 5ae713a; T-353: the live run on Tor's public network passed (5a535a9)
  • T-381: service-live.yml checks that a detached run outlives the end of its login session (0054e03)
  • T-381: service-live.yml ends the login session while it is open (314668a)
  • T-353 (partial): Tor's throughput measured through chutney's network, and two defects that it found repaired (a94718a)
  • T-381: done, a detached run outlives the end of its login session on a runner's systemd (2793402)
  • T-353: done, the Tor road through the box's proxy of a cage's ports on Tor's public network; GitHub #63 closed (57f345a)
  • GitHub #63 closed: TODO/github.txt says so (57f345a's record closed the row before the issue was) (1bafa9d)
  • The notes of v1.0.0-beta.4: the work since 7855981 (T-381, T-414, T-419, T-418, the pump's writes and the Tor road's two threads of T-353) (22eba9d)
  • The notes of v1.0.0-beta.4: the sizes of the dry run of its code (1bafa9d, run 41337605530), the same as at 0872994 (889fda2)
  • T-420: done, the strict stand-in tells a frame in flight after an operator's lost link apart; T-421 filed for the relay's operator (6fafa28)
  • T-422 (partial): the checks of the release no longer wait on railway.new's limit for anonymous visitors (74974dd)
  • T-422: the row railway skips on railway.new's limit at 74974dd (--only railway) (99b29dc)
  • T-424: -M leaves no control socket when its connection fails first; T-423: the session lock's test waits 2 s for a release; T-422: done (4e79a1f)