Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5d6ea01
test: feature-gate embedded desktop webdriver
darwvin-dev Aug 19, 2026
9dc7e45
test: add packaged desktop e2e scripts
darwvin-dev Aug 19, 2026
e0989c6
test: isolate packaged desktop e2e capability
darwvin-dev Aug 19, 2026
b47d0f0
test: configure embedded packaged desktop webdriver
darwvin-dev Aug 19, 2026
cc3a370
test: exercise packaged desktop operator paths
darwvin-dev Aug 19, 2026
659a807
test: keep desktop webdriver surface minimal
darwvin-dev Aug 19, 2026
b0632b6
ci: run packaged Tauri desktop smoke tests
darwvin-dev Aug 19, 2026
004cbba
chore: add one-shot packaged e2e dependency wiring
darwvin-dev Aug 19, 2026
2c0d563
chore: trigger one-shot e2e wiring from PR synchronization
darwvin-dev Aug 19, 2026
7307f95
chore: resolve e2e dependency locks without system packages
darwvin-dev Aug 19, 2026
2341bd5
test: wire feature-gated packaged desktop webdriver
github-actions[bot] Aug 19, 2026
d75c4f4
security: gate packaged webdriver to test-only builds
darwvin-dev Aug 19, 2026
365e5ec
docs: document packaged desktop e2e boundary
darwvin-dev Aug 19, 2026
2a81eda
docs: record packaged desktop e2e gate
darwvin-dev Aug 19, 2026
110fe80
ci: isolate packaged e2e data at runtime
darwvin-dev Aug 19, 2026
92440d3
chore: diagnose packaged e2e audit advisory
darwvin-dev Aug 19, 2026
d1487f1
chore: remove npm audit diagnostic helper
github-actions[bot] Aug 19, 2026
a41d626
test: replace webdriverio with dependency-free W3C client
darwvin-dev Aug 19, 2026
4fd423d
test: drive packaged desktop through raw W3C webdriver
darwvin-dev Aug 19, 2026
3997ed6
test: remove webdriverio configuration
darwvin-dev Aug 19, 2026
c158054
test: remove webdriverio smoke spec
darwvin-dev Aug 19, 2026
6250143
security: forbid javascript webdriverio dependency graph
darwvin-dev Aug 19, 2026
c6d210e
docs: document dependency-free W3C desktop client
darwvin-dev Aug 19, 2026
8a56829
chore: refresh dependency lock after webdriverio removal
darwvin-dev Aug 19, 2026
95fe4f0
test: prune vulnerable webdriverio dependency graph
github-actions[bot] Aug 19, 2026
3bca063
docs: record strict audit for raw webdriver client
darwvin-dev Aug 19, 2026
7711491
ci: harden Linux dependency installs for desktop e2e
darwvin-dev Aug 19, 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
98 changes: 96 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,19 @@ jobs:
- uses: actions/checkout@v6

- name: Install Tauri and SSH fixture dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo apt-get update
sudo apt-get install -y \
timeout --foreground 8m sudo apt-get \
-o Acquire::Retries=5 \
-o Acquire::http::Timeout=30 \
-o Acquire::https::Timeout=30 \
update
timeout --foreground 12m sudo apt-get \
-o Acquire::Retries=5 \
-o Acquire::http::Timeout=30 \
-o Acquire::https::Timeout=30 \
install -y --no-install-recommends \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
Expand Down Expand Up @@ -128,3 +138,87 @@ jobs:

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

packaged-e2e:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
WEBKIT_DISABLE_DMABUF_RENDERER: "1"
NO_AT_BRIDGE: "1"
DEBIAN_FRONTEND: noninteractive
steps:
- uses: actions/checkout@v6

- name: Isolate application data
run: |
echo "XDG_CONFIG_HOME=$RUNNER_TEMP/remoteopsx-e2e/config" >> "$GITHUB_ENV"
echo "XDG_DATA_HOME=$RUNNER_TEMP/remoteopsx-e2e/data" >> "$GITHUB_ENV"
echo "XDG_CACHE_HOME=$RUNNER_TEMP/remoteopsx-e2e/cache" >> "$GITHUB_ENV"
mkdir -p \
"$RUNNER_TEMP/remoteopsx-e2e/config" \
"$RUNNER_TEMP/remoteopsx-e2e/data" \
"$RUNNER_TEMP/remoteopsx-e2e/cache"

- name: Install packaged desktop dependencies
run: |
timeout --foreground 8m sudo apt-get \
-o Acquire::Retries=5 \
-o Acquire::http::Timeout=30 \
-o Acquire::https::Timeout=30 \
update
timeout --foreground 12m sudo apt-get \
-o Acquire::Retries=5 \
-o Acquire::http::Timeout=30 \
-o Acquire::https::Timeout=30 \
install -y --no-install-recommends \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
libssl-dev \
build-essential \
xvfb \
dbus-x11

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_VERSION }}

- name: Cache cargo
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
src-tauri/target
key: ${{ runner.os }}-e2e-rust-${{ env.RUST_VERSION }}-${{ hashFiles('src-tauri/Cargo.lock') }}

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm

- name: Install JS dependencies
run: npm ci

- name: Build test-only Tauri binary
run: |
npm run e2e:build
test -x src-tauri/target/debug/remoteopsx

- name: Verify production config stays closed
run: |
node - <<'NODE'
const fs = require('node:fs');
const config = JSON.parse(fs.readFileSync('src-tauri/tauri.conf.json', 'utf8'));
if (config.app?.withGlobalTauri !== false) throw new Error('production withGlobalTauri must remain false');
const cargo = fs.readFileSync('src-tauri/Cargo.toml', 'utf8');
if (!cargo.includes('tauri-plugin-wdio-webdriver = { version = "1", optional = true }')) {
throw new Error('embedded WebDriver dependency must remain optional');
}
NODE

- name: Packaged desktop smoke
run: dbus-run-session -- xvfb-run -a npm run e2e
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The project follows Semantic Versioning. Pre-release progression for a release l
- Tunnel policies add desired-state autostart/auto-reconnect reconciliation.
- Versioned encrypted workspace backup/restore uses OpenSSL AES-256-CBC with PBKDF2, excludes keyring secrets, clears stale local credentials for restored server IDs, and restores transactionally with tunnel autostart disabled.
- Operator Center provides one place to manage persistent alerts, transfers, multi-host operations, tunnel policies, and backup/restore.
- Packaged desktop CI now launches the feature-gated Tauri binary under WebDriver and smoke-tests the Operations Dashboard, universal palette, backend Runbook dry-run, and settings persistence through real Tauri IPC/SQLite.

### Security
- SSH first contact now uses an app-managed `known_hosts` store with SHA-256 fingerprint preview and explicit Trust / Replace / Remove actions; terminal, one-shot exec, SCP, and tunnels all require strict host-key verification.
Expand All @@ -32,6 +33,7 @@ The project follows Semantic Versioning. Pre-release progression for a release l
- Known keyring secrets are registered in a central redaction layer and masked from buffered SSH output, IPC errors, every textual runbook result field, backend diagnostics, and exported text; profile metadata, user runbooks, snippets, and persisted tunnel endpoint text reject known stored credentials before SQLite persistence.
- Existing saved credentials are preloaded from keyring references during startup on a best-effort basis, so redaction and persistence guards are active before the first connection attempt; historical user-controlled SQLite text is also scrubbed from logical database values when it contains a known secret.
- Workspace restore never revives an unrelated stale keyring credential sharing a restored server ID; all restored IDs have local credentials explicitly cleared after the database transaction commits.
- Packaged E2E keeps the embedded WebDriver dependency optional and immediately feature-gated; the production config keeps `withGlobalTauri=false` and does not enable the WDIO execute/mock IPC bridge.
- CI and tagged-release preflight contain source-level regression gates that reject weakened SSH/RDP trust and password-in-argv patterns.

### Reliability
Expand Down
30 changes: 30 additions & 0 deletions docs/PACKAGED_DESKTOP_E2E.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Packaged Desktop E2E

RemoteOpsX has a Linux CI gate that drives the actual Tauri desktop binary rather than only the Vite renderer.

## Test boundary

The E2E build uses the Cargo feature `e2e` and the configuration overlay `src-tauri/tauri.e2e.conf.json`. The overlay gives the test build a separate application identifier and replaces the capability set with the normal main-window permissions plus `wdio-webdriver:default`.

The production `tauri.conf.json` continues to set `withGlobalTauri` to `false`. The richer WDIO execute/mock bridge is intentionally not installed or enabled. `tauri-plugin-wdio-webdriver` is an optional Rust dependency and is registered only under `#[cfg(feature = "e2e")]`, so ordinary debug/release builds do not start a WebDriver listener.

The JavaScript test side deliberately has no WebdriverIO dependency. `e2e/run.mjs` uses Node's built-in `fetch` to speak the W3C WebDriver HTTP protocol directly to the feature-gated embedded server on loopback. This keeps the E2E dependency graph small and keeps `npm audit --audit-level=high` applicable to the complete JavaScript dependency tree without exceptions.

The initial WebdriverIO client experiment was removed after the locked dependency graph produced high-severity audit findings. The reduced graph was regenerated from `package.json` and verified with locked install, strict high-severity audit, the production security source gates, and the normal frontend build before the temporary lock-refresh workflow removed itself.

## CI flow

The `packaged-e2e` job:

1. installs the Linux libraries required to build/run Tauri plus Xvfb and a DBus session;
2. uses isolated XDG config/data/cache directories inside the runner;
3. builds an unbundled debug binary with the `e2e` feature and the E2E config overlay;
4. verifies the production config and optional dependency boundary;
5. starts the real desktop binary under Xvfb/DBus;
6. waits for the loopback W3C WebDriver status endpoint, opens a session, and runs `e2e/run.mjs` against the real window.

## Smoke coverage

The suite proves that the packaged app window boots into the persisted Operations Dashboard, the universal command palette is interactive, Runbook Studio can validate/dry-run through the Rust backend, and settings can be saved and read back through real Tauri IPC and SQLite.

The suite does not store credentials, contact real servers, or execute SSH commands.
Loading
Loading