Skip to content

Releases: Radiergummi/tsrelay

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 27 Oct 11:08
Immutable release. Only release title and notes can be modified.
v1.1.1
d84391f

What's Changed

  • Apply the architecture review: one owner per responsibility, less homegrown code by @Radiergummi in #81

Full Changelog: v1.1.0...v1.1.1

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 09:11
Immutable release. Only release title and notes can be modified.
v1.1.0
5a38995

A small release with one fix to how the CLI follows hook changes. Upgrade both the relay and your CLIs to get it; any mix of 1.0 and 1.1 keeps working as before.

Fixed

  • Hook changes made while a tunnel was down now reach the CLI when it reconnects. If a hook was renamed or made public while tsrelay http or tsrelay attach was disconnected, the CLI kept showing the old URL until the hook's next change. On reconnect, the relay now sends each hook's current state, numbered so that it can't undo a newer change that arrives first. This needs a 1.1 relay and a 1.1 CLI. With a 1.0 relay, a 1.1 CLI behaves as 1.0 did.
  • Website: search results link to the page's URL rather than its .html file.

Upgrading

Nothing to change. The store format is unchanged, so 1.1.0 and 1.0.0 can be swapped either way. The manifests in deploy/ pin 1.1.0.

Verifying this release

Binaries and the image come with SLSA build provenance and SBOM attestations:

gh attestation verify tsrelay_linux_amd64 --owner Radiergummi
gh attestation verify oci://ghcr.io/radiergummi/tsrelay:1.1.0 --owner Radiergummi

What's Changed

  • Post-v1 polish: search URLs, code-tab labels, 405 pins, outage renames by @Radiergummi in #75

Full Changelog: v1.0.0...v1.1.0

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 23 Oct 17:14
Immutable release. Only release title and notes can be modified.
v1.0.0
f7a52a6

tsrelay delivers HTTP callbacks from your tailnet to apps running on your laptop. Production calls the relay, laptops dial out to it, and your tailnet policy decides who may send and receive.

v1.0.0 is the first stable release. From now on, changes within 1.x only add things to what you build against: the HTTP API, policy grants, the Tsrelay-* headers and 56x statuses, serve configuration, the CLI (commands, flags, environment variables, exit codes and --json output) and the tunnel protocol. Any v1.x CLI works with any v1.y relay. Compatibility has the full promise, and Security model and limitations says what the relay guarantees and what it doesn't.

Upgrading from 0.6

Hooks carry over: the store format is unchanged, and a relay upgraded from 0.6.0 keeps every hook and setting. Check these before you upgrade:

  • The default capability is now tsrelay.mazetti.me/cap/relay. Relays that set --cap-name (TSRELAY_CAP_NAME) are unaffected.
  • Grants: maxHookTTL is now maxHookTtl (the old spelling still parses), and "channels": [] now matches nothing; leave channels out to mean every channel. The relay now logs keys in a grant value it doesn't know, such as a misspelled channels.
  • serve flags and their TSRELAY_* variables were renamed for one naming scheme; Configuration lists them all. An old variable left in the environment is ignored.
  • OAuth client secrets: append ?ephemeral=false&preauthorized=true, or the relay joins your tailnet as an ephemeral device that is removed after being offline. The client needs the auth_keys scope and must be allowed to assign tag:tsrelay.
  • Kubernetes: the manifests in deploy/ pin 1.0.0, meet the Pod Security restricted profile, and no longer set a namespace (kubectl apply -n <namespace>).
  • The API is strict about what it doesn't understand: unknown body fields, and unknown query parameters on writes, are refused with 422 unsupported_field; field names match exactly.

New

  • Restarts keep their promises. On SIGTERM, calls waiting for a tunnel get 503 shutting_down with Retry-After: 5, calls already delivered get --shutdown-timeout (20s) to finish, and the CLI reconnects to the restarted relay on its own.
  • Bounded memory. --capture-total-bytes (128 MiB) bounds what the inspector keeps of all calls together; Running a relay has a sizing rule.
  • Ready means ready. The relay gets its TLS certificate before /readyz reports ready, and a slow disk no longer stalls calls.
  • Operator docs: sizing, backups, restarts, failover, suggested alerts and a runbook for the 56x statuses.
  • Metrics: tsrelay_build_info, tsrelay_inspector_bytes, and the standard Go and process metrics. The audit log is written whatever --log-level says.
  • CLI: --json errors carry the relay's problem document, the CLI's own error codes are documented, and hooks delete and stop report every failure. A command killed by a signal exits 128+N.

Security

  • Call paths longer than 8 KiB are refused (414 path_too_long).
  • Responses from your app are served with a Content-Security-Policy sandbox, so a page it serves through a hook can't use the relay's origin.
  • Header spellings with underscores, such as X_Forwarded_For, are stripped like the dashed ones.
  • The CLI prints control characters a sender puts in a path escaped, so a call can't send your terminal escape sequences.
  • tsrelay update downloads the release and its checksum from GitHub itself; the relay only names the version.

Verifying this release

Binaries and the image come with SLSA build provenance and SBOM attestations:

gh attestation verify tsrelay_linux_amd64 --owner Radiergummi
gh attestation verify oci://ghcr.io/radiergummi/tsrelay:1.0.0 --owner Radiergummi

macOS binaries are signed and notarized. tsrelay is an independent project, not affiliated with or endorsed by Tailscale Inc.

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 21 Oct 15:16
Immutable release. Only release title and notes can be modified.
v0.6.0
58bb615

tsrelay 0.6 gives the relay's URLs and the CLI's tunnels one owner each. Every route now lives in one place, and the tests go through the handler the relay actually serves. tsrelay http and tsrelay attach run on one shared tunnel session, which fixes several cases where a dropped or renamed hook was handled wrongly. Read Upgrading for the two stricter rules.

Upgrading from 0.5

  • Channel names can't end in .json or .html. /channels/team.json means the channel team as JSON, so a channel named team.json would show up as a different channel in the web UI. Creating a hook in such a channel is now refused with 422. Hooks that already exist in one keep working, but their channel page won't load; move them to another channel.
  • Wrong methods get 405. A request with a method other than GET or HEAD, on a path that exists but doesn't take that method (PUT /hooks, OPTIONS /hooks), now gets 405 with an Allow header instead of 404. GET and HEAD still reach the web UI on any path.
  • No CLI update is needed. A 0.5 CLI works against a 0.6 relay.

Fixed

  • /channels/team.payments.json returned 404 instead of the channel team.payments as JSON. Any channel name with a dot was affected.
  • tsrelay attach exited when one of its hooks was deleted while it was disconnected, though its other hooks were fine. It now drops that hook and keeps serving the rest.
  • A hook the relay had just taken away (replaced by another tunnel, revoked or deleted) could be attached again if the tunnel reconnected at that moment. The relay refused it, and tsrelay http could even recreate a hook its owner had just deleted.
  • Hooks the relay took away stayed in a background tunnel's record, so tsrelay ps still listed them and tsrelay stop <path> still matched them.
  • tsrelay http --background recorded the old hook ID when it recreated its hook on the first connect.
  • The inspector measured time to first byte to when the response status was sent on to the caller. It now measures to when the app's response headers arrived, as the audit log and metrics already did.
  • A .json or .html on an install script or document (/install.sh.json, /openapi.html) served it under the wrong type. Now it's refused with 406.

Changed

  • tsrelay attach prints the hook and channel line again after a hook is renamed or its public URL changes, as tsrelay http always did.
  • In the inspector, refused calls are marked as refused. When live updates stop, the web UI says why: the stream was refused, or too many are open. Keyboard shortcuts no longer fire while a dialog is open.
  • A refused tunnel attach names the hook it was refused for, in the problem's new hook field.

What's Changed

  • Add a run skill that starts and drives the dev relay by @Radiergummi in #68
  • Give the web UI's query views and cache policy one owner each; drop the bundle budget by @Radiergummi in #67
  • Web follow-ups: mark refused calls, explain stopped live updates, modal-aware shortcuts by @Radiergummi in #69
  • Give a running tunnel one owner: client.Session for http and attach by @Radiergummi in #70
  • Give the URL space one owner: api.NewRouter by @Radiergummi in #71
  • Make the session the one owner of the hooks it dials by @Radiergummi in #72

Full Changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 14:19
Immutable release. Only release title and notes can be modified.
v0.5.0
7f56ebf

tsrelay 0.5 tightens who can see and do what on a relay. Every access rule now lives in one place, and a test checks every route for every kind of identity. Several access bugs are fixed on the way, and some policies are deliberately stricter, so read Upgrading before you deploy.

Upgrading from 0.4

  • Update the CLI. API writes without a body must now be sent as application/json too. A 0.4 CLI doesn't do that, so tsrelay hooks delete and tsrelay hooks rotate-url fail with 415 against a 0.5 relay. Everything else, tunnels included, keeps working. The CLI offers to update when the relay's version differs; tsrelay update does it directly.
  • Only people are admins. A tagged node whose grant has the admin role no longer gets admin rights. Give the admin role to users.
  • Admin grants are scoped to their channels. An admin sees and deletes only hooks in channels their admin grant's channels patterns match. A grant without channels covers every channel, so only admin grants that list channels are affected.
  • public is scoped to its grant's channels. A grant that carries "public": true allows public hooks only in the channels that grant names. A public hook in a channel the owner's public grant doesn't cover stops answering internet calls: it answers 404, like an unknown URL, and the owner still sees those calls in the inspector. A grant without channels covers every channel, so check only grants with public that list channels, and that they include the channels your public hooks use. GET / now returns public as a list of channel patterns.
  • Event streams need a role. A node with no role on the relay can no longer open event streams, and each node may hold at most 8 at once.
  • Building from source: the SBOM and license texts are now built rather than committed. make build builds them; a plain go build binary works, but has no licenses page or tsrelay licenses. Release binaries and images are unaffected.

Fixed

  • Tagged nodes with the admin role could list, read and delete everyone's hooks.
  • Admin grants ignored their channel scope.
  • Editing, rotating, replaying or testing a hook didn't re-check the owner's receiver role and channel. Owners can still always delete their hooks.
  • After a channel change made from one node, a tunnel on another node could keep receiving a channel it isn't granted, for up to 60 seconds.
  • A held call could follow a renamed hook and be forwarded with a stale path prefix. Held calls are now routed again from their original address once a tunnel attaches, their sender is identified again, and every delivery checks that the tunnel may still serve the hook.
  • Replaying a public call skipped the check that the owner may still receive public calls.
  • Event streams were unlimited, unfiltered once opened, and never re-checked who was watching.
  • The audit log could record a hook update after that hook's deletion.
  • A call whose sender hung up right after the last byte of the response was counted as sender_canceled. It now counts as ok, because the response went out in full.

Changed

  • Calls refused because of their channel go into their own list of 10 per hook, marked refused: true. They no longer push delivered calls out of the inspector or send events.
  • Status codes are consistent across the API: a hook you can't see is 404, one you can see but may not change is 403, and a setting your grant doesn't allow is a 422 on that field. API responses are Cache-Control: no-store.
  • The container image is built on Go 1.27.2.

What's Changed

  • Give the hook–tunnel lifecycle one owner by @Radiergummi in #56
  • Route hook updates through the lifecycle by @Radiergummi in #57
  • Announce hook changes in the order they were made by @Radiergummi in #58
  • Put every authorization rule in one access package by @Radiergummi in #59
  • Build the SBOM instead of committing it by @Radiergummi in #63
  • Keep TestStreamCap from deadlocking on a refused stream's body by @Radiergummi in #64
  • Bump golang from 1.27.1-bookworm to 1.27.2-bookworm in the images group across 1 directory by @dependabot[bot] in #60
  • Bump golang.org/x/mod from 0.41.0 to 0.42.0 in the go group across 1 directory by @dependabot[bot] in #61
  • Bump the web group across 1 directory with 7 updates by @dependabot[bot] in #65
  • Give a call's outcome one owner by @Radiergummi in #66

Full Changelog: v0.4.1...v0.5.0

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 19 Oct 07:48
Immutable release. Only release title and notes can be modified.
v0.4.1
ae70a9c

What's Changed

Full Changelog: v0.4.0...v0.4.1

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 16:59
Immutable release. Only release title and notes can be modified.
v0.4.0
6a699ae

tsrelay 0.4 adds public hooks for third-party webhooks, a reworked web UI, and a CLI that runs tunnels in the background and updates itself. It also changes the API and the error statuses, so read Upgrading before you deploy.

Upgrading from 0.3

  • Reinstall the CLI once. The API moved off /api/v1, so a 0.3 CLI can't talk to a 0.4 relay, and tsrelay update is new in this release. Run curl -fsSL https://<your relay>/install.sh | sh, or irm https://<your relay>/install.ps1 | iex on Windows. From then on, tsrelay update keeps the CLI on the relay's version.

  • API URLs changed. Every resource now lives at a single URL. Its JSON, the web UI page and its live event stream all come from that URL, picked by Accept: / (the entry document, formerly /api/v1/me), /hooks, /hooks/{id}, /hooks/{id}/calls, /channels, and so on. Each resource has its own event stream, which replaces the separate /api/v1/events. GET /openapi.json describes the API.

  • Error statuses changed. Tunnel and transport failures now use their own statuses, so they can't be mistaken for your app's 502, 503 or 504:

    Error Was Now
    tunnel_unavailable 503 561
    tunnel_overloaded 503 562
    tunnel_lost 502 563
    upstream_unreachable 502 564
    upstream_timeout 504 565
    body_stalled (new) — 408

    Clients that don't know these statuses treat them as 500. Tsrelay-Error still names the error.

  • Bodies aren't captured by default. The inspector still records every call's metadata and headers, but keeps request and response bodies only if the hook or the relay opts in. Opt in with --hook-capture-default on the relay, or with capture: true (--capture) per hook. Replaying a call needs its request body captured.

New

  • Public hooks: a hook can be made reachable from the internet through Tailscale Funnel, for webhooks from providers such as Stripe, GitHub or Twilio. Both sides have to opt in. The operator runs tsrelay serve --funnel and grants "public": true, and you run tsrelay http 3000 --public. The public URL is a secret; tsrelay hooks rotate-url replaces it. Your app sees Tsrelay-Sender-Public: true on these calls, including replays of them. The relay doesn't verify provider signatures, so your app has to; see SECURITY.md.
  • Background tunnels: tsrelay http --background returns once the tunnel is attached; tsrelay ps, logs and stop manage it.
  • Self-update: tsrelay update replaces the CLI with the relay's version, checked against the release's checksum. The CLI offers to update when the versions differ, and admins are told when a newer release exists (--update-check=false turns that off).
  • Channels in the web UI: /channels and /channels/{name} list hooks by channel, and channel names link there.
  • Reworked hook form: a URL-prefixed path, a channel picker, duration presets, expiry quick picks, a live preview of the hook, and a "Reachable from" choice for public hooks.
  • Explained CLI errors: errors say what went wrong, why, and how to fix it, also as --json. Shell completions now complete hooks, channels and targets.
  • Licenses: tsrelay licenses, /licenses and a footer list the open-source components tsrelay ships, generated from an SBOM that CI checks against the dependencies.

Fixed

  • tsrelay update fetches a Windows binary's checksum from the right URL.
  • A relay's write guard no longer treats public callbacks as API writes.
  • Live timestamps in the web UI keep ticking when calls arrive faster than once a second.
  • tsrelay http keeps a reaped hook's public state when it recreates it.
  • Public tokens are compared in constant time, and every incoming X-Forwarded-* header is stripped, not only on public calls.
  • Shell completions work even when a TSRELAY_* variable is invalid.
  • A data race between the transport and the call log on aborted calls.
  • go-git is updated to 5.19.2. It is only in the SBOM tooling, not the binary.

What's Changed

  • Disable go cache by @Radiergummi in #16
  • Guard the request body's counts against the transport still reading it by @Radiergummi in #42
  • Serve public hooks to the internet through Tailscale Funnel by @Radiergummi in #36
  • Keep TestTunnelLostBeforeHeaders from seeing the app's empty answer by @Radiergummi in #41
  • Keep relative timestamps live and drop the header's role list by @Radiergummi in #31
  • Split the README into "Using tsrelay" and "Running a relay" by @Radiergummi in #30
  • Serve the API and web UI from shared, content-negotiated URLs by @Radiergummi in #32
  • Make channels navigable in the web UI, backed by /channels resources by @Radiergummi in #34
  • Use a 56x status range for tunnel failures, and capture bodies only on opt-in by @Radiergummi in #33
  • Add a footer and an open-source licenses page by @Radiergummi in #35
  • Explain CLI errors, and complete hooks, channels and targets by @Radiergummi in #37
  • Fix the build: check tsrelay licenses' arguments with arity by @Radiergummi in #44
  • Update go-git to 5.19.2 by @Radiergummi in #45
  • Give async queries in web tests 5 s instead of 1 s by @Radiergummi in #46
  • Rework the hook create and edit forms by @Radiergummi in #38
  • Run tunnels in the background with --background by @Radiergummi in #39
  • Update the CLI to the relay's version, and tell admins about new releases by @Radiergummi in #40
  • Fetch a Windows binary's checksum without its .exe in tsrelay update by @Radiergummi in #47

Full Changelog: v0.3.1...v0.4.0

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 16 Oct 07:41
Immutable release. Only release title and notes can be modified.
v0.3.1
eb6e9e9

What's Changed

  • Use alternate variables to configure the rcodesign version by @Radiergummi in #15

Full Changelog: v0.3.0...v0.3.1

v0.2.2

Choose a tag to compare

@github-actions github-actions released this 15 Oct 11:39
Immutable release. Only release title and notes can be modified.
v0.2.2

What's Changed

  • Add OpenTelemetry metrics and tracing, pprof, benchmarks and a performance baseline by @Radiergummi in #3
  • Fix the forwarder's port exhaustion and pool copy buffers, and rebuild the CLI on cobra, fang and lipgloss by @Radiergummi in #4
  • Replace the server-rendered pages with a React single-page UI by @Radiergummi in #5
  • Bump node from 24-bookworm-slim to 25-bookworm-slim by @dependabot[bot] in #7
  • Bump the web group in /web with 2 updates by @dependabot[bot] in #9
  • Bump the go group across 1 directory with 5 updates by @dependabot[bot] in #8
  • Bump react-router from 7.18.4 to 8.4.0 in /web by @dependabot[bot] in #11
  • Fix the image build, and tag, attest and SBOM the release image by @Radiergummi in #12

New Contributors

Full Changelog: v0.1.0...v0.2.2

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 18:29
Immutable release. Only release title and notes can be modified.
v0.1.0

What's Changed

  • Label the container image with its source repository by @Radiergummi in #1

New Contributors

Full Changelog: https://github.com/Radiergummi/tsrelay/commits/v0.1.0