Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
db0e705
feat: scaffold Go module, main entry, and 12 tunnel subcommand stubs
drewr Jun 5, 2026
01d1d68
feat: add internal packages, test fakes, and build scripts
drewr Jun 5, 2026
9f1fca5
test: add E2E tests for Phase 1 requirements and build script test step
drewr Jun 5, 2026
451eac9
feat(04-01): implement shared exec infrastructure
drewr Jun 5, 2026
2b68f05
fix(exec): safe type assertion in ParseTypedMessage for messages with…
drewr Jun 6, 2026
0093044
feat(04-03): implement listen subcommand with streaming JSON and sign…
drewr Jun 6, 2026
e206b49
feat(04-02): implement list, update, delete tunnel subcommands
drewr Jun 6, 2026
9ee50d6
fix: fix fake binary typed JSON output and e2e interaction tests
drewr Jun 6, 2026
5ad86b2
test(05-background-daemon-01): add failing tests for state package
drewr Jun 6, 2026
ff4bf0f
feat(05-background-daemon-01): implement state package
drewr Jun 6, 2026
b188661
test(05-background-daemon-01): add failing tests for pidfile multi-PI…
drewr Jun 6, 2026
5483f15
feat(05-background-daemon-01): implement pidfile multi-PID format
drewr Jun 6, 2026
d320e70
test(05-background-daemon-01): add failing tests for process health
drewr Jun 6, 2026
2722267
feat(05-background-daemon-01): implement process health utilities
drewr Jun 6, 2026
fc6801d
feat(05-background-daemon-02): implement daemon supervisor
drewr Jun 6, 2026
386abd0
feat(05-background-daemon-02): implement daemonize fork
drewr Jun 6, 2026
4bc1b60
feat(05-background-daemon-02): add --detach and --name flags to listen
drewr Jun 6, 2026
e411285
feat(05-background-daemon-02): implement tunnel run supervisor entry …
drewr Jun 6, 2026
ee12a93
feat(05-background-daemon-02): add daemon-listen mode to fake binary
drewr Jun 6, 2026
1861ae2
feat(05-background-daemon-03): implement tunnel ps command
drewr Jun 6, 2026
f4d864a
feat(05-background-daemon-03): implement tunnel stop command
drewr Jun 6, 2026
3573d5e
feat(05-background-daemon-03): implement tunnel logs command
drewr Jun 6, 2026
a63fb27
feat(05-background-daemon-03): implement tunnel status command
drewr Jun 6, 2026
6d7be22
test(05-background-daemon-03): add e2e tests for process commands
drewr Jun 6, 2026
4a53385
feat(06-service-installation-01): add kardianos/service dependency
drewr Jun 6, 2026
090337a
feat(06-service-installation-01): implement svcconfig with config dir…
drewr Jun 6, 2026
fb842cd
test(06-service-installation-01): add failing tests for svcunit
drewr Jun 6, 2026
1c9a88d
feat(06-service-installation-01): implement svcunit with kardianos/se…
drewr Jun 6, 2026
342d0a6
test(06-02): add failing test for install command validation
drewr Jun 6, 2026
cb31642
feat(06-02): implement tunnel install command
drewr Jun 6, 2026
b292fe5
feat(06-02): implement tunnel uninstall and start commands
drewr Jun 6, 2026
fe1a9a8
feat(06-02): extend tunnel stop with service stop fallback
drewr Jun 6, 2026
1a26740
feat(06-02): add --session flag to tunnel run command
drewr Jun 6, 2026
576a44d
feat(06-02): add unified status view with installed check
drewr Jun 6, 2026
a873d85
test(06-02): add e2e tests for config persistence and unified status
drewr Jun 6, 2026
7404dba
chore(06-02): update stub test to reflect all 12 subcommands implemented
drewr Jun 6, 2026
c56d636
feat(connect-lib): scaffold workspace with foundation modules (Wave 1)
drewr Jun 6, 2026
d77a376
feat(connect-lib): populate business logic layer — DatumCloudClient, …
drewr Jun 6, 2026
a275bf5
feat(connect-lib): full ListenNode + HeartbeatAgent with auth panic f…
drewr Jun 6, 2026
5f9d6ee
feat(connect-lib): plugin-mode binary with tunnel CRUD and --project …
drewr Jun 6, 2026
23c861d
fix(connect-lib): resolve compilation errors and serde bugs — E2E ver…
drewr Jun 6, 2026
f95515e
fix: listen ready message type match, gotReady, startup timeout
drewr Jun 7, 2026
7b64d03
chore(git): ignore target/
drewr Jun 7, 2026
c566b81
chore(git): ignore target/
drewr Jun 7, 2026
0f07d55
port(11-01): feat: scope listen_key per project so connectors do not …
drewr Jun 8, 2026
f9de874
feat(nix): add flake.nix providing Rust + Go dev shell
drewr Jun 8, 2026
d4c0597
port(11-02): feat: stream tunnel setup progress and fail fast on iroh…
drewr Jun 8, 2026
a1fe363
port(11-02): fix: progress steps require observedGeneration to match …
drewr Jun 8, 2026
2f77240
port(11-02): feat: annotate each progress line with the Kubernetes re…
drewr Jun 8, 2026
837ca2e
port(11-03): feat: heartbeat manual mode so CLI tunnel does not fan o…
drewr Jun 8, 2026
32f7902
port(11-03): fix: default to Datum relays in any build, warn on n0 fa…
drewr Jun 8, 2026
ce45ddd
port(11-03): feat: log when heartbeat registers a connector
drewr Jun 8, 2026
9c07387
port(11-03): fix: recover from auth 401s without forcing a logout
drewr Jun 8, 2026
0b51846
port(11-03): fix: classify refresh errors so transient blips do not b…
drewr Jun 8, 2026
263f096
port(11-03): fix: recover heartbeat from deleted lease instead of loo…
drewr Jun 8, 2026
5109b48
port(11-04): feat: retry quota-check timeouts on tunnel resource creates
drewr Jun 8, 2026
d830554
port(11-04): feat: update_project is idempotent — skip the PATCH on n…
drewr Jun 8, 2026
9e611a3
feat(12-01): add inquire 0.7 dep to bin/Cargo.toml
drewr Jun 8, 2026
7c9b536
feat(12-01): install reload-capable tracing subscriber
drewr Jun 8, 2026
4445c83
feat(12-01): --id flag + picker-with-auto-adopt + tracing silence
drewr Jun 8, 2026
cf4e22f
chore: add Taskfile.yaml for build/install/test workflows
drewr Jun 8, 2026
eccee6e
feat(12-02): --id semantics — resume by name and validate against --e…
drewr Jun 8, 2026
4382932
feat(12-02): expose --id on go plugin listen
drewr Jun 8, 2026
69d1c02
test(11.5-02): add failing tests for env.Build refactor + RequireConn…
drewr Jun 9, 2026
9f3c59c
feat(11.5-02): rewrite env.Build as pass-through + add RequireConnect…
drewr Jun 9, 2026
28078ba
test(11.5-02): add e2e tests for DATUM_CONNECT_DIR enforcement
drewr Jun 9, 2026
7f8834b
feat(11.5-02): wire RequireConnectDir into main.go, clean discovery.g…
drewr Jun 9, 2026
fe255a7
test(11.5-03): add failing tests for default_location Result
drewr Jun 9, 2026
efe22d0
feat(11.5-03): replace XDG fallback with Result + rename env var
drewr Jun 9, 2026
cbdcf70
test(11.5-03): rename clap env attribute to DATUM_CONNECT_DIR
drewr Jun 9, 2026
c80f724
feat(11.5-03): update bin call site for Result + exit 64 on missing dir
drewr Jun 9, 2026
b9539b6
test(11.5-04): add failing tests for buildConfig EnvVars
drewr Jun 9, 2026
adeba49
feat(11.5-04): populate EnvVars with per-service DATUM_CONNECT_DIR
drewr Jun 9, 2026
c99c163
feat(11.5-04): remove per-service state subdir on uninstall
drewr Jun 9, 2026
6de414c
feat(12-03): add reqwest to bin Cargo.toml
drewr Jun 9, 2026
86ca158
feat(12-03): scaffold bin/src/progress.rs — Mode, callbacks, format_t…
drewr Jun 9, 2026
2d9ab12
feat(12-03): implement await_tunnel_progress + verify_endpoints
drewr Jun 9, 2026
d647a7b
feat(12-03): wire await_tunnel_progress + verify_endpoints, delete sl…
drewr Jun 9, 2026
a85249b
feat(12-04): runtime select-loop — ctrl_c + login watch + 10s progres…
drewr Jun 9, 2026
0df0ada
chore(12-05): reconcile JSON event contract — explicit case arms in G…
drewr Jun 9, 2026
754351b
docs(12-05): document JSON event contract inline in progress.rs and m…
drewr Jun 9, 2026
fee81c2
refactor(13-01): flatten state layout — remove PROJECTS_DIR, flatten …
drewr Jun 10, 2026
ef6a99f
refactor(13-01): remove per-service DATUM_CONNECT_DIR override from s…
drewr Jun 10, 2026
5d641d9
fix(13-08): update detach message wording per resolution table #2
drewr Jun 10, 2026
8dd9f1c
docs(13-08): remove exit code 75 from documentation per resolution ta…
drewr Jun 10, 2026
ef263ef
test(13-08): verify e2e tests pass with new detach wording
drewr Jun 10, 2026
041f526
feat(13-06): refactor ExternalTokenSource — helper exec at startup, r…
drewr Jun 10, 2026
15444b9
fix(13-06): replace DATUM_ACCESS_TOKEN check with DATUM_SESSION detec…
drewr Jun 10, 2026
e61d96c
refactor(13-06): remove DATUM_ACCESS_TOKEN from Go plugin env.Build()
drewr Jun 10, 2026
216b3e3
refactor(13-09): ApiEnv::default calls from_env_with_host_override; m…
drewr Jun 10, 2026
128655c
feat(13-02): add required --project flag to tunnel install
drewr Jun 10, 2026
04db444
feat(13-02): tunnel run loads project from YAML and rejects mismatch
drewr Jun 10, 2026
59ce82a
feat(13-02): tunnel start loads project from YAML and rejects mismatch
drewr Jun 10, 2026
02134e8
refactor(13-03): restrict tunnel run to --name only; reject all other…
drewr Jun 10, 2026
0a7f2df
refactor(13-03): simplify ServiceArgs to only produce tunnel run --na…
drewr Jun 10, 2026
6221d92
feat(13-04): add CredentialsHelperPath to TunnelConfig
drewr Jun 10, 2026
3a1031a
feat(13-04): capture DATUM_CREDENTIALS_HELPER at install time
drewr Jun 10, 2026
8e31772
feat(13-04): set DATUM_CREDENTIALS_HELPER in service unit EnvVars fro…
drewr Jun 10, 2026
3e9e120
feat(13-07): add rbaccheck package with SSAR query support
drewr Jun 10, 2026
9fedb0f
refactor(13-05): tunnel update — confirm server-only mutation (no YAM…
drewr Jun 10, 2026
3fd0ccf
feat(13-07): call rbaccheck during tunnel install
drewr Jun 10, 2026
dc497bc
feat(13-05): tunnel run queries server for live label/endpoint at sta…
drewr Jun 10, 2026
006cb28
fix(env): auto-compute DATUM_CONNECT_DIR from $HOME/.datumctl/connect…
drewr Jun 10, 2026
4bbe4d3
fix: prepend https:// to DATUM_API_HOST when scheme missing
drewr Jun 10, 2026
5a6aac8
fix: start setup timer earlier, floor verify_budget at 5s
drewr Jun 10, 2026
c8d853e
feat: pretty-print setup progress with checkmarks, timings, and headers
drewr Jun 10, 2026
83a2a63
fix: always write progress text to stderr regardless of --json mode
drewr Jun 10, 2026
1d506df
fix: retry on 503 during endpoint verification
drewr Jun 10, 2026
bc20d63
fix: proxy verification retries indefinitely with periodic 10s status
drewr Jun 10, 2026
958ab4d
fix: suppress usage/error on signal-initiated shutdown
drewr Jun 10, 2026
35b437b
docs: add README with architecture, layout, build/run instructions
drewr Jun 10, 2026
ecd54a3
fix: Go e2e tests after connect-plugin directory move
drewr Jun 10, 2026
d585470
fix: install:go task dir to connect-plugin/ where binary is built
drewr Jun 10, 2026
090a34e
docs: refer agents to readme
drewr Jun 10, 2026
5dc9f1d
feat(17-02): pass tunnel name to Rust binary via DATUM_CONNECT_TUNNEL…
drewr Jun 12, 2026
1a2731f
feat(17-per-tunnel-state): add Repo::listen_key_for_tunnel() with leg…
drewr Jun 12, 2026
08b15c7
feat(17-per-tunnel-state): add ListenNode::new_with_key() constructor
drewr Jun 12, 2026
1ba1451
feat(17-per-tunnel-state): update listen command for per-tunnel key l…
drewr Jun 12, 2026
768affa
fix: increase startup timeout from 5m to 10m for slow Envoy propagation
drewr Jun 12, 2026
fd8dfdb
fix: list command shows all tunnels by filtering on tunnel- prefix
drewr Jun 13, 2026
4b303b1
fix: auto-detect ConnectorClass and fix project flag passing
drewr Jun 13, 2026
9ff5775
fix: print tunnel progress every 10s instead of one-shot warning at 30s
drewr Jun 13, 2026
96eb64a
fix: Ctrl-C now deletes tunnel (HTTPProxy, Connector, local state)
drewr Jun 13, 2026
680e48d
fix: single-line progress status (no reason/message sub-lines)
drewr Jun 13, 2026
c68290a
fix: Ctrl-C cleanup prints same resource list as delete command
drewr Jun 13, 2026
bf2b344
fix: tunnel listen end-to-end fixes for extension-server mode
drewr Jun 20, 2026
19a29bd
ci: add GoReleaser release workflow and GitHub Actions
drewr Jun 20, 2026
6b53baa
fix(tests): remove committed test binaries and hardcoded author paths
0xmc Jun 22, 2026
5a24cac
fix(tests): update svcunit tests to reflect Phase 13 design
0xmc Jun 22, 2026
98b1da6
fix: eliminate double-Wait race in signals.Forward
0xmc Jun 22, 2026
1ade42b
ci: checkout datumctl alongside connect for go mod replace
0xmc Jun 22, 2026
731a719
fix(tests): fix four e2e test failures
0xmc Jun 22, 2026
5d6f69b
ci: fix datumctl checkout path for go mod replace
0xmc Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Release

on:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
rust-cross:
strategy:
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
name: linux-amd64
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
name: linux-arm64
- target: x86_64-apple-darwin
os: macos-latest
name: darwin-amd64
- target: aarch64-apple-darwin
os: macos-latest
name: darwin-arm64
- target: x86_64-pc-windows-gnu
os: ubuntu-latest
name: windows-amd64.exe
- target: aarch64-pc-windows-gnu
os: ubuntu-latest
name: windows-arm64.exe
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install Linux arm64 cross-compiler
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Install Windows cross-compiler
if: contains(matrix.target, 'windows')
run: sudo apt-get update && sudo apt-get install -y mingw-w64
- name: Build Rust binary
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: x86_64-w64-mingw32-gcc
CARGO_TARGET_AARCH64_PC_WINDOWS_GNU_LINKER: aarch64-w64-mingw32-gcc
run: cargo build --release -p datum-connect --target ${{ matrix.target }}
working-directory: connect-lib
- name: Rename binary with platform suffix
run: |
cp connect-lib/target/${{ matrix.target }}/release/datum-connect${{ contains(matrix.target, 'windows') && '.exe' || '' }} \
/tmp/rust-bin/datum-connect-${{ matrix.name }}
shell: bash
- name: Upload Rust binary
uses: actions/upload-artifact@v4
with:
name: rust-${{ matrix.name }}
path: /tmp/rust-bin/datum-connect-${{ matrix.name }}

goreleaser:
needs: rust-cross
runs-on: ubuntu-latest
defaults:
run:
working-directory: connect-plugin
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: connect-plugin/go.mod
- name: Download all Rust binaries
uses: actions/download-artifact@v4
with:
path: /tmp/rust-artifacts
- name: Stage Rust binaries for goreleaser
run: |
mkdir -p ../dist/rust
find /tmp/rust-artifacts -type f -exec cp {} ../dist/rust/ \;
ls -la ../dist/rust/
- name: Install Syft CLI
run: curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36 changes: 36 additions & 0 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: testing

on:
push:
paths:
- 'connect-plugin/**/*.go'
- 'connect-plugin/go.mod'
- 'connect-plugin/go.sum'

jobs:
testing:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Checkout datumctl
uses: actions/checkout@v6
with:
repository: datum-cloud/datumctl
path: datumctl-dep
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: connect-plugin/go.mod
- name: Rewrite replace directive for CI
run: go mod edit -replace go.datum.net/datumctl=../datumctl-dep
working-directory: connect-plugin
- name: Verify dependencies
run: go mod verify
working-directory: connect-plugin
- name: Build
run: go build ./...
working-directory: connect-plugin
- name: Test (known-good packages only)
run: go test -timeout 5m ./internal/daemon ./internal/env ./internal/exec ./internal/pidfile ./internal/state ./internal/svcconfig
working-directory: connect-plugin
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
target/
*.so
connect-plugin/datumctl-connect
connect-plugin/fake-datum-connect-test
connect-plugin/internal/daemon/fake-datum-connect
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Read @README.md
171 changes: 171 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Datum Connect Plugin

A `datumctl` plugin (`datumctl connect tunnel listen ...`) that wraps the Rust
[`datum-connect`](connect-lib/) binary to manage Datum Connect tunnels.

## Architecture

```
datumctl connect tunnel listen ...
┌─────────────────────────────────────┐
│ Go supervisor (datumctl-connect) │ reads stdout for JSON events
│ connect-plugin/tunnel/listen/ │ forwards stderr to terminal
│ connect-plugin/internal/* │
│ │
│ ┌─────────────────────────────┐ │
│ │ Rust binary (datum-connect)│ │ stderr → user (progress, ✓ lines)
│ │ connect-lib/bin/src/ │ │ stdout → Go supervisor (JSON)
│ │ connect-lib/lib/ │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
```

- **Go supervisor** (`connect-plugin/main.go`): datumctl plugin binary, parses
tunnel-ready events from stdout, forwards signals (Ctrl+C), manages
startup/grace timeout.
- **Rust binary** (`connect-lib/bin/`): headless tunnel agent driven by
iroh + HTTPProxy APIs. Progress text goes to stderr; JSON lifecycle
events go to stdout.
- **Rust library** (`connect-lib/lib/`): shared types, Kube API client,
DatumCloud API bindings, heartbeat agent, tunnel service.

## Directory Layout

```
connect/
├── connect-plugin/ # Go plugin source
│ ├── main.go # Plugin entrypoint
│ ├── tunnel/ # Cobra subcommands (listen, run, list, …)
│ │ └── listen/main.go # Primary: spawns Rust binary, reads events
│ ├── internal/ # Go support packages
│ │ ├── binary/ # Rust binary discovery
│ │ ├── daemon/ # Background daemonisation
│ │ ├── env/ # Child environment builder (DATUM_SESSION, etc.)
│ │ ├── exec/ # Typed JSON message parser
│ │ ├── logfile/ # Log file management
│ │ ├── output/ # Formatted output (table/json/yaml)
│ │ ├── pidfile/ # PID tracking
│ │ ├── rbaccheck/ # Service-account RBAC validation
│ │ ├── signals/ # OS signal relay
│ │ ├── state/ # Daemon/run state persistence
│ │ ├── svcconfig/ # System service config builders
│ │ └── svcunit/ # systemd unit file generation
│ ├── e2e_test.go # E2E tests (manifest, listen)
│ ├── e2e_interaction_test.go # E2E tests (install, service, PID)
│ ├── go.mod / go.sum
│ ├── scripts/ # Build/release helpers
│ ├── testdata/ # Test fixtures
│ └── fake-datum-connect-test # Test helper binary
├── connect-lib/ # Rust workspace
│ ├── Cargo.toml
│ ├── bin/ # Binary crate (datum-connect)
│ │ └── src/
│ │ ├── main.rs # Entrypoint, CLI, Listen handler
│ │ └── progress.rs # Tunnel progress rendering (✓ / ○)
│ └── lib/ # Library crate (connect-lib)
│ └── src/
│ ├── datum_cloud/ # API client, auth, env
│ ├── heartbeat.rs # HeartbeatAgent
│ ├── tunnel.rs # TunnelService
│ └── …
├── flake.nix # Nix dev shell
├── Taskfile.yaml # Build/test/install tasks
└── README.md
```

## Install

```bash
datumctl plugin install datum-cloud/connect
```

Downloads the pre-built archive from the [latest GitHub release](https://github.com/datum-cloud/connect/releases) and places both binaries in `~/.datumctl/plugins/`.

## Components

### connect-plugin — Go supervisor (`connect-plugin/`)

The datumctl plugin binary. Parses JSON events from the Rust subprocess's stdout, forwards signals, manages startup/grace timeout.

```bash
# Build (debug)
cd connect-plugin && go build -o datumctl-connect .

# Test
cd connect-plugin && go test -timeout 5m ./internal/...

# Install to ~/.datumctl/plugins/
cp connect-plugin/datumctl-connect ~/.datumctl/plugins/
```

Requires **Go ~1.25.8+** (see `connect-plugin/go.mod`).

### connect-lib — Rust library + binary (`connect-lib/`)

The tunnel agent. The `datum-connect` binary is a headless tunnel daemon driven by iroh + HTTPProxy APIs. It is also published as a **library crate** (`connect-lib/lib/`) exposing shared types, Kube API client, DatumCloud API bindings, heartbeat agent, and tunnel service — suitable for embedding in other clients such as [Datum Desktop](https://github.com/datum-cloud/app).

```bash
# Build binary (debug)
cd connect-lib && cargo build -p datum-connect

# Run unit tests across the workspace
cd connect-lib && cargo test

# Package crate for downstream use
cd connect-lib && cargo package -p connect-lib
```

Requires **Rust stable** (see `connect-lib/rust-toolchain.toml`).

## Developing

The canonical build and test commands are in `Taskfile.yaml`. Each task delegates to the underlying Go or Rust toolchain in the relevant subdirectory.

```bash
# Build both binaries (debug)
task build

# Release build with LTO + strip
task build:release

# Run all tests
task test

# Run Go or Rust tests individually
task test:go
task test:rust
```

Helper scripts are also available in `connect-plugin/scripts/`.

## Nix

A dev shell with Go, Rust, task, pkg-config, and openssl is available:

```bash
nix develop
```

The packaged Rust binary can also be built with Nix:

```bash
nix build
```

## Releases

Push a semver tag (`vX.Y.Z`); `.github/workflows/release.yml` cross-compiles `datum-connect` (Rust) via a matrix of OS runners, then runs GoReleaser to produce per-platform archives containing both `datumctl-connect` and `datum-connect`, plus `checksums.txt`.

The plugin is versioned independently of both `datumctl` and the `datum-connect` Rust binary. After a release, update the `Plugin` manifest at `datum-cloud/datumctl-plugins/index.yaml`.

## Key Design Decisions

| Decision | Rationale |
|----------|-----------|
| Two-binary architecture | Rust binary ships independently; Go supervisor handles dispatch, daemonisation, signal management. |
| `--json` mode always on | Go supervisor parses line-delimited JSON events from stdout; human text goes to stderr. |
| No `DATUM_ACCESS_TOKEN` in child env | Rust binary uses `DATUM_CREDENTIALS_HELPER` + `DATUM_SESSION` to exec helper for token. |
| Proxy verification retries indefinitely | Datum Cloud can take time to settle; user sees periodic `○ waiting for proxy …` messages every 10s. |
| State isolation | Plugin uses `~/.local/share/datumctl/connect/` — no OAuth files, no selected_context. |
Loading