Skip to content

Commit 99171b1

Browse files
Merge pull request #124 from datum-cloud/automatic-app-updates
Automatic app updates
2 parents c7b2fcd + 408726b commit 99171b1

File tree

19 files changed

+1362
-426
lines changed

19 files changed

+1362
-426
lines changed

.github/workflows/bundle.yml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,21 @@ jobs:
269269
contents: write
270270
# Only create releases for v* tags (no rolling release on main)
271271
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
272+
outputs:
273+
# Matches desktop updater: pre-release tags (e.g. v1.0.0-beta.1) => beta channel + GitHub prerelease
274+
is_prerelease: ${{ steps.channel.outputs.prerelease }}
272275
steps:
276+
- name: Classify stable vs beta (semver pre-release tag)
277+
id: channel
278+
run: |
279+
TAG_NAME="${{ github.ref_name }}"
280+
V="${TAG_NAME#v}"
281+
if [[ "$V" == *-* ]]; then
282+
echo "prerelease=true" >> $GITHUB_OUTPUT
283+
else
284+
echo "prerelease=false" >> $GITHUB_OUTPUT
285+
fi
286+
273287
- name: Set Version Info and Paths
274288
id: set_paths
275289
run: |
@@ -305,8 +319,8 @@ jobs:
305319
with:
306320
name: ${{ env.RELEASE_NAME }}
307321
tag_name: ${{ env.RELEASE_TAG }}
308-
make_latest: true
309-
prerelease: false
322+
make_latest: ${{ steps.channel.outputs.prerelease != 'true' }}
323+
prerelease: ${{ steps.channel.outputs.prerelease == 'true' }}
310324
body: |
311325
Version: ${{ env.RELEASE_VERSION }}
312326
Tag: ${{ env.RELEASE_TAG }}
@@ -321,7 +335,8 @@ jobs:
321335
update-homebrew:
322336
needs: [release]
323337
runs-on: ubuntu-latest
324-
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
338+
# Stable tags only — beta/pre-release builds must not replace the Homebrew cask
339+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && needs.release.outputs.is_prerelease == 'false'
325340
steps:
326341
- name: Download macOS artifacts
327342
uses: actions/download-artifact@v7

.github/workflows/manual-release.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
workflow_dispatch:
55
inputs:
66
version:
7-
description: "Release version tag (e.g. v0.0.1)"
7+
description: "Release tag (stable: v1.2.3 — beta: v1.2.3-beta.1; hyphen after v => GitHub pre-release, in-app beta channel)"
88
required: true
99
type: string
1010
publish_docker:
@@ -188,6 +188,18 @@ jobs:
188188
permissions:
189189
contents: write
190190
steps:
191+
- name: Classify stable vs beta (semver pre-release tag)
192+
id: channel
193+
env:
194+
VERSION_TAG: ${{ inputs.version }}
195+
run: |
196+
V="${VERSION_TAG#v}"
197+
if [[ "$V" == *-* ]]; then
198+
echo "prerelease=true" >> $GITHUB_OUTPUT
199+
else
200+
echo "prerelease=false" >> $GITHUB_OUTPUT
201+
fi
202+
191203
- name: Download All Artifacts
192204
uses: actions/download-artifact@v7
193205
with:
@@ -214,8 +226,9 @@ jobs:
214226
with:
215227
name: DatumConnect ${{ inputs.version }}
216228
tag_name: ${{ inputs.version }}
229+
# Do not mark as "latest" — tag pushes from bundle.yml own that; beta still gets prerelease: true
217230
make_latest: false
218-
prerelease: false
231+
prerelease: ${{ steps.channel.outputs.prerelease == 'true' }}
219232
draft: false
220233
files: artifacts/**/*
221234

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ rand = "0.9"
3636
reqwest = { version = "0.12", features = ["rustls-tls", "json"] }
3737
rustls = { version = "0.23", features = ["ring"] }
3838
serde = { version = "1", features = ["derive"] }
39+
semver = "1.0"
3940
serde_json = "1.0.145"
4041
serde_yml = "0.0.12"
4142
tokio = { version = "1.34.0", features = ["full"] }

README.md

Lines changed: 18 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,170 +1,37 @@
11
## Datum Tunnels
22

3-
This repo is broken into 3 components, a CLI, GUI app, and shared-core library that the CLI & GUI draw on.
3+
CLI, GUI app, and shared library for exposing local environments to the internet.
44

5-
### Download the app
6-
[![Download for macOS](https://img.shields.io/badge/Download-macOS-000000?logo=apple&logoColor=white)](https://github.com/datum-cloud/datum-connect/releases/latest/download/Datum.dmg)
7-
[![Download for Windows](https://img.shields.io/badge/Download-Windows-0078D6?logo=windows&logoColor=white)](https://github.com/datum-cloud/datum-connect/releases/latest/download/Datum-setup.exe)
8-
[![Download for Linux](https://img.shields.io/badge/Download-Linux-FCC624?logo=linux&logoColor=black)](https://github.com/datum-cloud/datum-connect/releases/latest/download/Datum.AppImage)
9-
10-
If a download fails, use the latest release page: https://github.com/datum-cloud/datum-connect/releases/latest
11-
12-
13-
### Required Tools
14-
* For all three crates: [`rust & cargo`](https://rust-lang.org/tools/install/)
15-
* For UI: [`dioxus`](https://dioxuslabs.com/learn/0.6/getting_started/)
16-
* specifically, install `dx` with `cargo install dioxus-cli`
17-
* if you have [`binstall`](https://github.com/cargo-bins/cargo-binstall?tab=readme-ov-file#installation), you can skip compiling `dx` from source by running `cargo binstall dioxus-cli`
18-
19-
### Running CLI commands:
20-
to run without compiling, use `cargo run` in the `cli` directory:
21-
22-
```
23-
cd cli
24-
cargo run -- --help
25-
```
26-
27-
### Local forward-proxy demo (no GUI)
28-
This exercises the CONNECT-based gateway flow that Envoy will use in staging/prod.
29-
30-
#### 1) Start a local DNS dev server (out-of-band)
31-
Use a non-`.local` origin (e.g. `datumconnect.test`):
32-
33-
```
34-
cargo run -p datum-connect -- dns-dev serve \
35-
--origin datumconnect.test \
36-
--bind 127.0.0.1:53535 \
37-
--data ./dns-dev.yml
38-
```
39-
40-
#### 2) Start the listen node (connector side)
41-
This prints the endpoint id and the iroh UDP bound sockets you must publish:
42-
43-
```
44-
cargo run -p datum-connect -- serve
45-
```
5+
### Download
466

47-
Copy the printed `dns-dev upsert` example, but run it via `cargo run -p datum-connect -- ...`
48-
and make sure the origin matches `datumconnect.test`. Quote IPv6 addresses like `"[::]:1234"`.
7+
**macOS (Homebrew):**
498

50-
#### 3) Verify TXT resolution
51-
The `serve` command prints the z-base-32 ID and the full DNS name. Query it with:
52-
53-
```
54-
dig +norecurse @127.0.0.1 -p 53535 TXT _iroh.<z32>.datumconnect.test
9+
```bash
10+
brew install datum-cloud/tap/desktop
5511
```
5612

57-
#### 4) Start the gateway in forward mode
13+
**Direct download:**
5814

59-
```
60-
cargo run -p datum-connect -- gateway \
61-
--port 8080 \
62-
--metrics-addr 127.0.0.1 \
63-
--metrics-port 9090 \
64-
--mode forward \
65-
--discovery dns \
66-
--dns-origin datumconnect.test \
67-
--dns-resolver 127.0.0.1:53535
68-
69-
Discovery modes:
70-
- `default`: iroh defaults (n0 preset).
71-
- `dns`: only the provided DNS origin/resolver.
72-
- `hybrid`: default + custom DNS.
73-
- metrics endpoint: `GET http://127.0.0.1:9090/metrics` (when `--metrics-addr` or `--metrics-port` is set)
74-
```
75-
76-
#### 5) Send a CONNECT request
77-
If your target TCP service is on `127.0.0.1:5173`:
78-
79-
```
80-
curl --proxytunnel -x 127.0.0.1:8080 \
81-
--proxy-header "x-iroh-endpoint-id: REPLACE_WITH_ENDPOINT_ID" \
82-
"http://127.0.0.1:5173"
83-
```
84-
85-
### GUI demo (browser tunnel)
86-
This mirrors the same flow, but uses the GUI to create the proxy entry.
15+
[![Download for macOS](https://img.shields.io/badge/Download-macOS-000000?logo=apple&logoColor=white)](https://github.com/datum-cloud/datum-connect/releases/latest/download/Datum.dmg)
16+
[![Download for Windows](https://img.shields.io/badge/Download-Windows-0078D6?logo=windows&logoColor=white)](https://github.com/datum-cloud/datum-connect/releases/latest/download/Datum-setup.exe)
17+
[![Download for Linux](https://img.shields.io/badge/Download-Linux-FCC624?logo=linux&logoColor=black)](https://github.com/datum-cloud/datum-connect/releases/latest/download/Datum.AppImage)
8718

88-
If you want a one-shot experience, run:
19+
[Latest release →](https://github.com/datum-cloud/datum-connect/releases/latest)
8920

90-
```
91-
./scripts/try-ui-demo.sh
92-
```
21+
### Development
9322

94-
It starts dns-dev, an HTTPS origin, the gateway, and the GUI, and waits for you to
95-
create a TCP proxy in the UI before visiting `https://localhost:5173` in the browser.
23+
**Requirements:** [Rust](https://rust-lang.org/tools/install/), [Dioxus CLI](https://dioxuslabs.com/learn/0.6/getting_started/) (`cargo install dioxus-cli` or `cargo binstall dioxus-cli`)
9624

97-
#### 1) Start `dns-dev`
98-
```
99-
cargo run -p datum-connect -- dns-dev serve \
100-
--origin datumconnect.test \
101-
--bind 127.0.0.1:53535 \
102-
--data ./dns-dev.yml
103-
```
25+
**Run the GUI:**
10426

105-
#### 2) Start a local HTTPS origin (so the browser uses CONNECT)
106-
```
107-
openssl req -x509 -nodes -newkey rsa:2048 -days 1 \
108-
-keyout /tmp/iroh-dev.key -out /tmp/iroh-dev.crt \
109-
-subj "/CN=localhost"
110-
openssl s_server -accept 5173 -cert /tmp/iroh-dev.crt -key /tmp/iroh-dev.key -www
111-
```
112-
113-
#### 3) Run the GUI (share the repo with CLI)
114-
```
115-
export DATUM_CONNECT_REPO=$(pwd)/.datum-connect-dev
27+
```bash
11628
cd ui
11729
dx serve --platform desktop
11830
```
11931

120-
#### 4) Create a proxy in the GUI
121-
Add a TCP proxy for `127.0.0.1:5173`.
122-
123-
#### 5) Start the listen node (uses the same repo)
124-
```
125-
cd ..
126-
export DATUM_CONNECT_REPO=$(pwd)/.datum-connect-dev
127-
cargo run -p datum-connect -- serve
128-
```
129-
Copy the printed `dns-dev upsert` example, but change the origin to `datumconnect.test`
130-
and run it via `cargo run -p datum-connect -- ...` (quote IPv6 addresses).
32+
**Run the CLI:**
13133

132-
#### 6) Start the gateway in forward mode
133-
```
134-
export DATUM_CONNECT_REPO=$(pwd)/.datum-connect-dev
135-
cargo run -p datum-connect -- gateway \
136-
--port 8080 \
137-
--metrics-addr 127.0.0.1 \
138-
--metrics-port 9090 \
139-
--mode forward \
140-
--discovery dns \
141-
--dns-origin datumconnect.test \
142-
--dns-resolver 127.0.0.1:53535
143-
```
144-
145-
#### 7) Start a local entrypoint that always tunnels through the gateway
146-
This avoids any browser proxy configuration. It listens on `127.0.0.1:8888` and
147-
uses CONNECT under the hood to reach the target:
148-
```
149-
cargo run -p datum-connect -- tunnel-dev \
150-
--gateway 127.0.0.1:8080 \
151-
--node-id REPLACE_WITH_ENDPOINT_ID \
152-
--target-host 127.0.0.1 \
153-
--target-port 5173
154-
```
155-
Now visit:
156-
```
157-
https://localhost:8888
158-
```
159-
You should see the `openssl s_server` status page (cipher list + handshake info).
160-
That output is expected and means the CONNECT request tunneled through the gateway
161-
to the local origin.
162-
163-
### Running the UI:
164-
165-
to run the UI, make sure you have rust, cargo, and dioxus installed:
166-
167-
```
168-
cd ui
169-
dx serve
34+
```bash
35+
cd cli
36+
cargo run -- --help
17037
```

lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ postcard.workspace = true
3030
quinn.workspace = true
3131
rand.workspace = true
3232
reqwest.workspace = true
33+
semver.workspace = true
3334
serde.workspace = true
3435
serde_json.workspace = true
3536
serde_yml.workspace = true

lib/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub use project_control_plane::ProjectControlPlaneClient;
1818
pub use repo::Repo;
1919
pub use state::*;
2020
pub use tunnels::{TunnelDeleteOutcome, TunnelService, TunnelSummary};
21-
pub use update::{UpdateChecker, UpdateInfo, UpdateSettings};
21+
pub use update::{UpdateChannel, UpdateChecker, UpdateInfo, UpdateSettings};
2222

2323
/// The root domain for datum connect urls to subdomain from. A proxy URL will
2424
/// be a three-word-codename subdomain off this URL. eg: "https://vast-gold-mine.iroh.datum.net"

lib/src/repo.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ use crate::{
1717
pub struct Repo(PathBuf);
1818

1919
impl Repo {
20+
/// Create a Repo from a path without opening/creating (for sync use cases like update install).
21+
pub fn from_path(path: PathBuf) -> Self {
22+
Self(path)
23+
}
2024
const CONNECT_KEY_FILE: &str = "connect_key";
2125
const LISTEN_KEY_FILE: &str = "listen_key";
2226
const GATEWAY_KEY_FILE: &str = "gateway_key";

0 commit comments

Comments
 (0)