Skip to content
Open
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
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Run the same unit suite developers run locally on every PR and on main.
# Packaging stays in release.yml; these tests are plain Node and do not need
# Electron or a matrix of OS runners.

name: CI

on:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# PR code runs npm ci / npm test; do not leave GITHUB_TOKEN in git config.
persist-credentials: false

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- run: npm ci

# Production deps only: dev-only tools (Vite/esbuild) may still report
# advisories that do not affect the packaged app.
- run: npm audit --omit=dev --audit-level=high

- run: npm test
12 changes: 9 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,15 @@ jobs:
- name: Package
run: npx electron-builder ${{ matrix.args }} --publish never
env:
# There is no signing certificate on a CI runner. Without this,
# electron-builder hunts for one and fails the macOS build.
CSC_IDENTITY_AUTO_DISCOVERY: false
# When WIN_CSC_LINK / CSC_LINK secrets are set, electron-builder signs
# the Windows installer and portable exe (or the macOS bundle). Without
# them, builds stay unsigned — see docs/security.md.
WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
# Only hunt the macOS keychain when a Developer ID cert is supplied.
CSC_IDENTITY_AUTO_DISCOVERY: ${{ secrets.CSC_LINK != '' && 'true' || 'false' }}

# The agent SDK carries the Claude CLI as an optional platform package,
# a 253MB binary that the app deliberately does not ship: the provider
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ releases/
# Local working notes and agent config, not part of the project
CLAUDE.md
.claude/

# Local product planning notes; keep out of the shared tree
PRD.md
81 changes: 81 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Changelog

All notable changes to CloudTerm are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions align
with [GitHub Releases](https://github.com/BradPerbs/cloudterm/releases).

## [1.3.1] - 2026-08-12

### Added

- GitHub Actions CI (`.github/workflows/ci.yml`) runs `npm test` on every pull
request and on pushes to `main`.
- CI runs `npm audit --omit=dev` to block high-severity vulnerabilities in
production dependencies.
- Optional Authenticode / macOS code signing in release builds when
`WIN_CSC_LINK` / `CSC_LINK` repository secrets are configured (certificate
**pending procurement** — builds stay unsigned until secrets are added). See
[docs/security.md](docs/security.md).
- [Security documentation](docs/security.md): VirusTotal/SmartScreen, signing,
dependency audit, vulnerability reporting.
- First-run assistant warning explaining that tools act on live sessions and
what each approval mode means.
- Confirm dialog before switching the assistant to **Never ask**.
- Contributor docs: [assistant approval modes](docs/assistant-approvals.md),
[RDP credential lifetime](docs/rdp-credentials.md), and
[IME composition plan](docs/ime-composition.md).

### Changed

- npm production and dev dependencies updated (`npm audit fix`); esbuild
overridden to a patched release for the dev toolchain.
- Default assistant approval mode is **Ask before changes** (`writes`): reads
run freely; mutating tools stop for approval.
- New installs ship with `allowLocalTools: false`.
- RDP passwords are cleared from the renderer as soon as CredSSP completes;
reconnect always re-fetches credentials from the vault. See
[RDP credentials](docs/rdp-credentials.md).
- Activity log redacts `rdpPassword` and `bmcPassword` in change diffs.

### Fixed

- Session log transcript files use a unique exclusive path per session so two
tabs in the same second cannot interleave into one file.
- First-run approval warning only clears after **Got it** (not Escape / backdrop).
- Assistant approval acknowledgement accepts only real booleans when loading
`assistant.json`.

## [1.3.0] - 2026-08-10

### Added

- Host monitoring with desktop notifications when a saved host stops answering.
- Launch CloudTerm at sign-in (Windows).
- Check for updates on every launch.
- BMC/IPMI web UI opens in a tab with auto-login.
- App icon on every platform (`build/icon.png`).

### Changed

- Host cards fit every protocol kind on one row.
- Distro icons halved to match on-screen draw size.
- Renderer dependencies kept out of the packaged app bundle.
- Monitor events kept out of the notifications bell.

## [1.2.1] - 2026-08-06

### Added

- Quick connect: type an address in the host picker and connect immediately.
- Windows install and update via `winget install CloudBlast.CloudTerm`. See
[docs/winget.md](docs/winget.md).

## [1.2.0]

Earlier releases are listed on
[GitHub Releases](https://github.com/BradPerbs/cloudterm/releases).

[Unreleased]: https://github.com/BradPerbs/cloudterm/compare/v1.3.0...HEAD
[1.3.0]: https://github.com/BradPerbs/cloudterm/releases/tag/v1.3.0
[1.2.1]: https://github.com/BradPerbs/cloudterm/releases/tag/v1.2.1
[1.2.0]: https://github.com/BradPerbs/cloudterm/releases/tag/v1.2.0
241 changes: 241 additions & 0 deletions PRD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
# CloudTerm — Product Requirements Document

| Field | Value |
|-------|-------|
| **Product** | CloudTerm |
| **Owner** | CloudBlast |
| **Version covered** | 1.3.0 (as shipped) |
| **Status** | Living document — current product + next roadmap |
| **License** | Fair-code (free to use/modify/share; commercial resale needs a CloudBlast license) |
| **Repo** | https://github.com/BradPerbs/cloudterm |

---

## 1. Vision

CloudTerm is a **desktop multi-protocol terminal workspace**: one window for SSH, SFTP, Telnet, serial, RDP, VNC, and BMC/IPMI, with encrypted local vault storage, optional CloudBlast cloud sync, and a local AI agent that can act through live sessions (with approval).

**North star:** Replace tool sprawl (PuTTY + WinSCP + RDP client + VNC + serial terminal + snippet managers) with a single, trustworthy, modern app that travels with the user’s setup across machines.

---

## 2. Problem

| Pain | Today without CloudTerm |
|------|-------------------------|
| Tool sprawl | Separate apps per protocol; repeated logins and context switching |
| Setup doesn’t travel | Hosts, keys, snippets, known hosts differ per laptop |
| AI is paste-driven | Assistants don’t see the live terminal; users copy/paste riskily |
| CloudBlast customers | Manually re-enter VPS details instead of seeing servers ready to connect |

---

## 3. Goals & non-goals

### Goals

1. **One workspace** for every common remote-access protocol on Windows, macOS, and Linux.
2. **Secrets stay local** — vault-locked encrypted storage; cloud sync encrypts before upload.
3. **CloudBlast differentiation** — free encrypted sync for everyone; auto host list for CloudBlast VPS customers.
4. **Session-aware AI** — local CLIs (Claude Code / Codex / OpenCode) with approval gates; no credential tools.
5. **Trustworthy distribution** — signed installs, predictable updates, clear fair-code terms.

### Non-goals (near term)

- Becoming a full IDE or browser-based terminal SaaS
- Replacing enterprise PAM / jump-box products
- Storing plaintext credentials in the cloud
- Shipping AI that can extract or export vault secrets
- Guaranteeing recovery if the vault password is forgotten

---

## 4. Personas

| Persona | Needs | Success looks like |
|---------|--------|-------------------|
| **Sysadmin / SRE** | Many hosts, jump hosts, tunnels, monitoring | Folders/tags/search; reconnect; uptime checks; activity log |
| **Developer** | SSH + SFTP + occasional RDP/VNC | Fast connect, split panes, snippets, remote edit |
| **CloudBlast customer** | Servers appear without manual entry | Sign in → VPS hosts ready |
| **Multi-machine user** | Same setup on laptop + desktop | Encrypted cloud snapshot restore on sign-in |
| **AI-assisted operator** | Agent reads session and runs approved commands | Clear approval UX; safe defaults |

---

## 5. Current product (v1.3)

### 5.1 User-facing capabilities

| Area | Capability |
|------|------------|
| **Sessions** | SSH, Telnet, serial; jump hosts; SOCKS/HTTP proxies; tabs & split panes (max 8); themes; find; broadcast; screenshots; session log |
| **Files** | SFTP (list/mkdir/delete/rename, transfers, resume, conflicts, drag-and-drop); remote edit → upload on save |
| **Networking** | Local / remote / dynamic port forwarding with traffic counters |
| **Desktops** | RDP (IronRDP WASM), VNC (noVNC, SSH-tunnelled), BMC/IPMI web UI (sandboxed webview + auto-login) |
| **Inventory** | Hosts, folders, tags, search, quick-connect; keychain (generate/import, Windows Hello/TPM); snippets with `{{placeholders}}` |
| **Import** | `~/.ssh/config`, PuTTY, MobaXterm |
| **Security** | App lock / vault (password or OS keystore); encrypted backup export/restore |
| **Cloud** | CloudBlast OAuth (PKCE, system browser); VPS server sync; encrypted cross-device snapshot |
| **Ops** | Host TCP monitoring + notifications; activity log; auto-update from GitHub Releases (winget on Windows) |
| **AI** | Claude Code / Codex / OpenCode; tools: hosts, sessions, terminal read/write, files, connect/disconnect — approval modes |
| **i18n** | In-app: en, zh, vi, pt, ru (README also offers Español — see gap below) |

### 5.2 Architecture (summary)

```
Renderer (React + xterm / IronRDP / noVNC)
↕ IPC + MessagePort (session bytes)
Main (Electron): store, vault, transport (ssh|telnet|serial),
sftp, tunnels, rdp, vnc, bmc, account, AI, monitor
```

- **Security defaults:** `contextIsolation`, no `nodeIntegration`, `sandbox`; secrets resolved in main; vault lock gates IPC.
- **Persistence:** `sessions.json`, `vault.json`, window state, cloud snapshot under Electron `userData`; UI prefs in `localStorage`.

### 5.3 Platforms & distribution

| Channel | Notes |
|---------|--------|
| GitHub Releases | NSIS + portable (Win), DMG/zip (macOS), AppImage (Linux) |
| winget | `CloudBlast.CloudTerm` — see `docs/winget.md` |
| Signing | **Unsigned** — Windows Authenticode cert **pending procurement**; CI ready when secrets are set — see [docs/security.md](docs/security.md) |

---

## 6. Requirements

### 6.1 Functional (must remain true)

| ID | Requirement |
|----|-------------|
| F1 | User can open SSH / Telnet / serial sessions from a host record without leaving the app |
| F2 | Credentials and private keys never leave the main process (RDP CredSSP path is the documented exception) |
| F3 | Vault lock blocks sensitive IPC until unlocked |
| F4 | SFTP and tunnels can reuse an active SSH connection |
| F5 | Cloud snapshot is encrypted client-side before upload |
| F6 | AI cannot read vault secrets; destructive/session-changing tools require approval unless user opts into a looser mode |
| F7 | Auto-update can be disabled (`CLOUDBLAST_UPDATE_DISABLED`) for air-gapped use |

### 6.2 Non-functional

| ID | Requirement | Current gap |
|----|-------------|-------------|
| N1 | PR builds run automated tests | **Shipped (M1):** `.github/workflows/ci.yml` on PRs and `main` |
| N2 | Installers code-signed on Windows (and ideally macOS) | **Pending** — cert procurement in progress; release CI wired for signing |
| N3 | Core paths (SSH connect, SFTP, lock/unlock) covered by automated smoke | Unit tests only; no E2E |
| N4 | Cold start acceptable for SSH-only users | RDP/VNC/WASM always in bundle weight |
| N5 | CJK IME composition usable in terminal | Known limitation — documented in `docs/ime-composition.md`; fix tracked in #7 |
| N6 | Marketing locales match in-app locales | Spanish README without in-app `es` |

---

## 7. Success metrics (suggested)

| Metric | Target (directional) |
|--------|----------------------|
| Crash-free sessions / week | Track via optional anonymous telemetry later; start with GitHub issue rate |
| Time-to-first-connect (fresh install → SSH) | < 2 minutes with import or CloudBlast sync |
| Update adoption (7-day) | Majority on latest within a week of release (post-signing) |
| Test gate | `npm test` green on every PR before merge |
| AI incident rate | Near-zero reports of unexpected `run_command` without approval on default settings |

---

## 8. Roadmap — bugs, enhancements, optimizations

Priorities: **P0** ship-blocking / trust / safety · **P1** product quality · **P2** polish & scale.

### 8.1 Bug fixes & reliability (P0–P1)

| Priority | Item | Rationale | Notes |
|----------|------|-----------|-------|
| **P0** | Add CI workflow that runs `npm test` on PRs | Regressions can ship with release-only CI | **Done** — `.github/workflows/ci.yml` |
| **P0** | Harden AI approval defaults + first-run warning | “Never ask” + `run_command` is high risk | **Done** — default `writes`, warning, confirm for `never`; see `docs/assistant-approvals.md` |
| **P0** | Audit RDP password lifetime in renderer/WASM | Documented secret exception | **Done** — see `docs/rdp-credentials.md`; tests in `test/rdp.test.js` |
| **P0** | Fix or quarantine IME composition positioning | Blocks CJK users; zh locale is shipped | **Quarantined (M1)** — `docs/ime-composition.md`; #7 open |
| **P1** | Session restore reconnect policy | Tabs restore without live sockets | Explicit “reconnect all” or per-tab option |
| **P1** | Update download UX | `autoDownload = true` may surprise corporate users | Optional “ask before download” |
| **P1** | Align Spanish: add `es` locale **or** remove es README until ready | Docs/product mismatch | |

### 8.2 Enhancements (P1–P2)

| Priority | Item | Rationale |
|----------|------|-----------|
| **P1** | Code-sign Windows (and ideally macOS) builds | SmartScreen, winget, enterprise adoption | **In progress** — Windows cert pending; `release.yml` ready |
| **P1** | Split oversized modules (`ipc.js`, `store.js`, `App.jsx`, `TerminalView.jsx`) by domain | Safer reviews; fewer regressions |
| **P1** | E2E smoke: mock SSH → SFTP → lock/unlock | Catch IPC/UI wiring unit tests miss |
| **P1** | SSH/SFTP integration tests (container or mock) | Core path under-tested vs edge protocols |
| **P1** | True 1024² app icon (replace upscaled soft cloud) | Documented in `resources/README.md` |
| **P1** | Rename npm package / clarify branding (`cloudblast-ssh` → `cloudterm`) | Contributor & packaging clarity |
| **P2** | Accessibility pass on dialogs + terminal chrome | Enterprise procurement |
| **P2** | Portable winget package parity | Mentioned as future in `docs/winget.md` |
| **P2** | Document env vars & `userData` layout under `docs/` | Support / IT / contributors |
| **P2** | Gradual TypeScript on `store` / `vault` / `ai/tools` | Catch IPC/secret-field shape bugs |

### 8.3 Optimizations (P2)

| Priority | Item | Rationale |
|----------|------|-----------|
| **P2** | Lazy-load RDP / VNC / noVNC chunks | Faster cold start for SSH-only users |
| **P2** | Cap / paginate activity & AI event retention more aggressively | Long-lived processes; large event buffers |
| **P2** | Parallelize `npm test` (today sequential `&&`) | Faster local + CI feedback |
| **P2** | Profile WebGL terminals under multi-pane load | Cap is 8 panes; validate GPU cost |

### 8.4 Explicitly out of scope for this PRD cycle

- Vault password recovery without user-held secret
- Server-side decryption of cloud snapshots
- AI tools that return private keys or vault DEK material

---

## 9. Security & threat notes (product constraints)

| Topic | Stance |
|-------|--------|
| Vault | Protects against disk theft; forgotten password = data unrecoverable by design |
| Cloud snapshot | Protects DB theft in transit/at rest; **not** a compromised CloudBlast app server acting as a malicious client |
| AI | Local CLIs under user accounts; approval modes are the control plane |
| BMC webview | Sandboxed but still untrusted vendor JS on LAN — treat as higher risk surface |
| RDP | Password must reach WASM for CredSSP — minimize lifetime and logging |
| OAuth | System browser + PKCE; client id `cloudblast-desktop` |

---

## 10. Milestones (suggested)

| Milestone | Scope | Exit criteria |
|-----------|--------|---------------|
| **M1 — Trust & gates** | PR CI for tests; AI default hardening; RDP password audit; IME fix plan | **Shipped** — CI on PRs; safer AI defaults; RDP docs + tests; IME quarantined in `docs/ime-composition.md` |
| **M2 — Distribution** | Code signing; icon quality; optional update consent | Signed Win (+ mac if feasible); reduced SmartScreen friction — **cert pending** |
| **M3 — Quality depth** | Module splits; E2E smoke; SSH/SFTP integration tests | Reviewable IPC surfaces; smoke green in CI |
| **M4 — Polish** | Locale alignment; lazy-load remoting; docs for env/`userData`; a11y pass | Marketing ↔ app parity; measurable startup win |

---

## 11. Open questions

1. Should cloud sync remain forever-free for non-CloudBlast users, or become tiered later?
2. Code signing: **Windows certificate procurement in progress**; macOS Developer ID deferred until after first signed Windows release.
3. Should “never ask” AI mode remain available, or be removed / hidden behind an advanced unlock?
4. Telemetry: opt-in crash/usage metrics, or stay fully silent?
5. Rename `appId` / package name in a major version, or keep `com.cloudblast.ssh` for upgrade continuity?

---

## 12. References

| Doc | Path / URL |
|-----|------------|
| User README | `README.md` (+ zh-CN, es, ru) |
| Changelog | `CHANGELOG.md` |
| Contributor docs | `docs/README.md` |
| Winget publish | `docs/winget.md` |
| Resources / icon notes | `resources/README.md` |
| License | `LICENSE` |
| Product site | https://cloudblast.io |

---

*This PRD describes the product as of v1.3.0 plus the M1 trust-and-gates
work on `feat/m1-trust-gates`. Update milestones when releases ship.*
Loading