Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,17 @@ jobs:

- name: Rust build
run: cargo build --manifest-path src-tauri/Cargo.toml

macos:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci || npm install
- run: npm run build
- run: cargo test --manifest-path src-tauri/Cargo.toml
- run: cargo build --manifest-path src-tauri/Cargo.toml
27 changes: 27 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,30 @@ jobs:
RemoteOpsX-x86_64.AppImage
src-tauri/target/release/bundle/deb/*.deb
src-tauri/target/release/bundle/rpm/*.rpm

macos:
runs-on: macos-14
steps:
- uses: actions/checkout@v4

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install JS dependencies
run: npm ci || npm install

- name: Build macOS bundles
run: npm run app:build

- name: Upload macOS release assets
uses: softprops/action-gh-release@v2
with:
files: |
src-tauri/target/release/bundle/dmg/*.dmg
src-tauri/target/release/bundle/macos/*.app.tar.gz
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# RemoteOpsX

**A unified Linux remote-operations workspace — not just another terminal.**
**A unified Linux and macOS remote-operations workspace — not just another terminal.**

RemoteOpsX is *MobaXterm + Remmina + a Netdata-lite + a server runbook engine*,
built for Linux operators. It combines remote access (SSH / SFTP / FTP / RDP / VNC),
built for Linux and macOS operators. It combines remote access (SSH / SFTP / FTP / RDP / VNC),
**agentless** live server-health monitoring, systemd diagnostics, log tooling,
SSH tunnels and **executable runbooks** into one keyboard-friendly desktop app.

> Working name: **RemoteOpsX**. Linux-first (Arch, Ubuntu, Debian, Fedora).
> Working name: **RemoteOpsX**. Supports macOS and Linux (Arch, Ubuntu, Debian, Fedora, openSUSE).

---

Expand Down Expand Up @@ -190,7 +190,7 @@ sudo dnf install openssh-clients sshpass freerdp tigervnc gnome-keyring
Prerequisites: **Rust** (stable, via rustup), **Node 18+**, and the Tauri Linux
system deps (`webkit2gtk-4.1`, `libappindicator`, etc).

On Arch, Debian/Ubuntu, Fedora, and openSUSE, install all runtime and build
On macOS, Arch, Debian/Ubuntu, Fedora, and openSUSE, install all runtime and build
dependencies interactively with:

```bash
Expand Down
21 changes: 20 additions & 1 deletion docs/distribution.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Distribution

RemoteOpsX ships as a native Linux desktop app. Docker is not required.
RemoteOpsX ships as a native Linux and macOS desktop app. Docker is not required.

## GitHub Releases

Expand All @@ -16,6 +16,25 @@ Expected release assets:
- `RemoteOpsX-x86_64.AppImage`
- Debian package (`.deb`)
- RPM package (`.rpm`)
- macOS disk image (`.dmg`)

## macOS

The macOS build uses the native Keychain for secrets and the built-in Screen
Sharing application for VNC. FreeRDP is installed with Homebrew for RDP.

Install build dependencies:

```bash
npm run deps:build
```

For an unpacked application bundle, the installer prepares runtime dependencies
before copying RemoteOpsX into `~/Applications`:

```bash
bash packaging/macos/install-app.sh path/to/RemoteOpsX.app
```

## Local AppImage Install

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"app:dev": "tauri dev",
"app:build": "tauri build",
"app:build:arch": "NO_STRIP=1 PKG_CONFIG_PATH=\"$PWD/scripts/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}\" tauri build",
"deps:runtime": "bash packaging/linux/bootstrap-dependencies.sh --runtime",
"deps:build": "bash packaging/linux/bootstrap-dependencies.sh --build"
"deps:runtime": "bash scripts/bootstrap-dependencies.sh --runtime",
"deps:build": "bash scripts/bootstrap-dependencies.sh --build"
},
"dependencies": {
"@tauri-apps/api": "^2.1.1",
Expand Down
58 changes: 58 additions & 0 deletions packaging/macos/bootstrap-dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
set -euo pipefail

MODE="runtime"
ASSUME_YES=0
DRY_RUN=0

for argument in "$@"; do
case "${argument}" in
--runtime) MODE="runtime" ;;
--build) MODE="build" ;;
--yes|-y) ASSUME_YES=1 ;;
--dry-run) DRY_RUN=1 ;;
--help|-h)
echo "Usage: $0 [--runtime|--build] [--yes] [--dry-run]"
exit 0
;;
*) echo "Unknown option: ${argument}" >&2; exit 2 ;;
esac
done

if [[ "$(uname -s)" != "Darwin" ]]; then
echo "This installer is for macOS. Use packaging/linux on Linux." >&2
exit 1
fi

if ! command -v brew >/dev/null 2>&1; then
echo "Homebrew is required to manage RemoteOpsX native dependencies." >&2
echo "Install it from https://brew.sh and run this command again." >&2
exit 1
fi

# OpenSSH, curl, Keychain and the built-in VNC Screen Sharing client ship with macOS.
formulae=(freerdp sshpass)
casks=()
if [[ "${MODE}" == "build" ]]; then
formulae+=(rust node pkg-config cmake llvm libvncserver)
fi

echo "RemoteOpsX will install ${MODE} dependencies with Homebrew:"
printf ' formula: %s\n' "${formulae[@]}"
if [[ "${#casks[@]}" -gt 0 ]]; then
printf ' cask: %s\n' "${casks[@]}"
fi

if [[ "${DRY_RUN}" -eq 1 ]]; then
exit 0
fi
if [[ "${ASSUME_YES}" -ne 1 ]]; then
read -r -p "Continue? [y/N] " reply
[[ "${reply}" =~ ^[Yy]$ ]] || { echo "Cancelled."; exit 0; }
fi

brew install "${formulae[@]}"
if [[ "${#casks[@]}" -gt 0 ]]; then
brew install --cask "${casks[@]}"
fi
echo "RemoteOpsX ${MODE} dependencies are installed."
24 changes: 24 additions & 0 deletions packaging/macos/install-app.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail

APP_PATH="${1:-RemoteOpsX.app}"
if [[ ! -d "${APP_PATH}" || "${APP_PATH}" != *.app ]]; then
echo "Application bundle not found: ${APP_PATH}" >&2
echo "Usage: $0 path/to/RemoteOpsX.app" >&2
exit 1
fi

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
if [[ "${REMOTEOPSX_SKIP_DEPENDENCIES:-0}" != "1" ]]; then
bash "${SCRIPT_DIR}/bootstrap-dependencies.sh" --runtime
fi

mkdir -p "${HOME}/Applications"
destination="${HOME}/Applications/RemoteOpsX.app"
if [[ -e "${destination}" ]]; then
read -r -p "Replace the existing ${destination}? [y/N] " reply
[[ "${reply}" =~ ^[Yy]$ ]] || { echo "Cancelled."; exit 0; }
rm -rf "${destination}"
fi
cp -R "${APP_PATH}" "${destination}"
echo "Installed RemoteOpsX to ${destination}"
9 changes: 9 additions & 0 deletions scripts/bootstrap-dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
case "$(uname -s)" in
Linux) exec bash "${ROOT_DIR}/packaging/linux/bootstrap-dependencies.sh" "$@" ;;
Darwin) exec bash "${ROOT_DIR}/packaging/macos/bootstrap-dependencies.sh" "$@" ;;
*) echo "RemoteOpsX dependency bootstrap supports Linux and macOS." >&2; exit 1 ;;
esac
4 changes: 2 additions & 2 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "remoteopsx"
version = "0.1.0"
description = "RemoteOpsX - unified Linux remote operations workspace"
description = "RemoteOpsX - unified remote operations workspace"
authors = ["RemoteOpsX"]
edition = "2021"
rust-version = "1.77"
Expand All @@ -24,7 +24,7 @@ serde_yaml = "0.9"
# Bundled SQLite so users need no system libsqlite to run the app.
rusqlite = { version = "0.32", features = ["bundled"] }
# OS Secret Service (keyring) so secrets never touch SQLite in plaintext.
keyring = { version = "3", features = ["linux-native"] }
keyring = { version = "3", features = ["linux-native", "apple-native"] }
# System-PTY driver for the interactive SSH terminal (system `ssh` binary).
portable-pty = "0.8"
anyhow = "1"
Expand Down
13 changes: 13 additions & 0 deletions src-tauri/src/vnc_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ fn vnc_bin() -> Option<&'static str> {

/// Launch an external VNC viewer for the given server.
pub fn launch(server: &Server, opts: &VncOptions) -> Result<()> {
#[cfg(target_os = "macos")]
{
let target = format!("vnc://{}:{}", server.host, server.vnc_port());
Command::new("open")
.arg(&target)
.spawn()
.map_err(|e| anyhow!("failed to launch macOS Screen Sharing: {e}"))?;
return Ok(());
}

#[cfg(not(target_os = "macos"))]
{
let bin = vnc_bin().ok_or_else(|| {
anyhow!("No VNC viewer found. Install one (e.g. `pacman -S tigervnc` / `apt install tigervnc-viewer`).")
})?;
Expand All @@ -57,4 +69,5 @@ pub fn launch(server: &Server, opts: &VncOptions) -> Result<()> {
cmd.spawn()
.map_err(|e| anyhow!("failed to launch {bin}: {e}"))?;
Ok(())
}
}
4 changes: 2 additions & 2 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
},
"bundle": {
"active": true,
"targets": ["appimage", "deb", "rpm"],
"targets": "all",
"category": "DeveloperTool",
"shortDescription": "Unified Linux remote operations workspace",
"longDescription": "RemoteOpsX is a Linux-first remote operations desktop app: SSH/SFTP/RDP/VNC access, live agentless server health monitoring, systemd diagnostics, logs, tunnels and executable runbooks.",
"longDescription": "RemoteOpsX is a Linux and macOS remote operations desktop app: SSH/SFTP/RDP/VNC access, live agentless server health monitoring, systemd diagnostics, logs, tunnels and executable runbooks.",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
Expand Down
Loading