# Dolphin — Proactive Security Patrol Plugin

[![Listed on dsh-plugin.org](https://dsh-plugin.org/badges/listed.svg)](https://dsh-plugin.org/plugins/ccr-wer/dsh-dolphin-security)

**This project is listed on the official dsh-plugin.org marketplace (Listed on dsh-plugin.org).**

> Transforming the penetration-testing methodology (Reconnaissance → Vulnerability Detection → Exploitation Validation → Reporting) into a **proactive defense patrol workflow**.
> Instead of waiting passively for alerts, Dolphin patrols your hosts on schedule — the way a dolphin swims its route.

Current release: **v0.2.5** (fixes the `@deepseek-ai/dsh-tools` version range in `peerDependencies` — prerelease versions only match within the same version tuple, so the previous range would fail assembly under strict peer validation; the new range aligns with and covers the DSH 0.1.5 series)

[简体中文](./README.md) | [English](./README_EN.md)

---

## ⚠️ Disclaimer

**This project is a technical research tool. Unauthorized penetration testing is strictly prohibited.**

- Use Dolphin **only** against systems and code that you own, or for which you have obtained **explicit written authorization**.
- Scanning, probing, or connecting to any third-party system without permission may violate applicable laws and regulations (including but not limited to cybersecurity and computer-misuse statutes).
- The authors accept no liability for any direct or indirect damage arising from the use, misuse, or abuse of this tool.
- **You must obtain explicit authorization before use.** The user bears full legal responsibility for their actions.

---

## Requirements

| Item | Requirement |
|---|---|
| OS | **Cross-platform**: Windows 10 / 11, Linux, macOS, WSL2 (see "Cross-Platform Support" below) |
| Node.js | **>= 20** (20 LTS or 22 LTS recommended) |
| Package manager | npm (bundled with Node.js) |
| Static analysis engine | **semgrep** (see installation below; the plugin can auto-provision it remotely in an isolated way when missing) |

---

## Cross-Platform Support

Dolphin runs across operating systems: **Windows / Linux / WSL / macOS** (Node.js >= 20), with zero OS-specific dependencies —

- **No hardcoded paths**: every data path is derived at runtime (`os.homedir()`, `os.tmpdir()`, the module's own location); Windows and POSIX paths both work.
- **Pure-JS SSH layer**: built on ssh2 (pure JavaScript, no platform-specific binaries). Controller and target can be any OS combination — a Linux controller scanning a Windows target, or vice versa; both directions are verified end-to-end.
- **POSIX-strict remote commands**: every command dispatched to the remote passes strict POSIX syntax validation (`dash -n`) plus single-quote escaping against injection.
- **Verified matrix**: full patrol loops (healthcheck → scan → report archive) verified for Windows controller ↔ Linux/WSL target and Linux (WSL) controller ↔ Windows target.

### Data & Paths (environment variables)

| Variable | Purpose | Default |
|---|---|---|
| `DOLPHIN_HOME` | Root of the host store and other data | Falls back to `DSH_HOME`, then `~/.dolphin` |
| `DSH_HOME` | DSH ecosystem data root (read by Dolphin as fallback) | `~/.dsh` |
| `DOLPHIN_REPORTS_DIR` | Patrol report output directory | `<plugin dir>/reports/` |
| `DOLPHIN_SEMGREP_CACHE` | Local cache of Linux wheels for remote provisioning | `~/.dolphin/semgrep-wheel-cache` |

The host store lives at `<data root>/dolphin-ssh-hosts.json` (atomic writes, 0600 permission semantics); patrol reports are sensitive data and excluded from the repository via `.gitignore`.

---

## Installation

### 1. Install dsh-dolphin-security (npm registry or GitHub — pick one)

```bash
# Option A: npm registry (recommended — published releases)
npm install dsh-dolphin-security

# Option B: GitHub repository (latest commits)
npm install git+https://github.com/CCR-WER/dsh-dolphin-security.git
```

> ⚠️ **Installation constraint**: always install this plugin via `npm install` (from the official npm registry or from the GitHub repository) as shown above. **Do not copy the package directory by hand** — this package is published through a `files` whitelist, and manual copies will be missing runtime files.
>
> **Requires the official DSH environment**: dsh-dolphin-security is a DSH (DeepSeek Harness, `@deepseek-ai/dsh`) ecosystem plugin. Once loaded by the official DSH host it registers two agent tools — `dolphin_scan` (local Semgrep scan) and `dolphin_patrol` (remote SSH patrol). Mount it inside an official DSH profile:
>
> ```bash
> dsh plugin --profile web add dsh-dolphin-security
> ```
>
> Outside a DSH host, `dolphin-patrol.js` / `dolphin-core.js` / `dolphin-ssh-core.js` remain directly usable as standalone libraries/CLI (see Features) and do not require a DSH environment.

### 2. Install dependencies (repo development)

```bash
npm install
```

> Pulls in `ssh2` (MIT) for remote SSH/SFTP capabilities.

### 3. Prerequisite: install semgrep and add it to PATH

Dolphin's scanning layer is powered by [semgrep](https://semgrep.dev) (LGPL-2.1). **semgrep must be installed and callable from the command line:**

```bash
pip install semgrep
```

Verify:

```bash
semgrep --version
```

A version string (e.g. `1.175.0`) confirms a working installation.

> **Windows note:** if `semgrep --version` reports "command not found", Python's `Scripts` directory is not on your PATH. Run `pip show semgrep`, replace the trailing `lib\site-packages` of the reported `Location` with `Scripts`, add that path to your system PATH, then restart your terminal.

---

## Features

### 1. Local scan (`--local`)

Run a static security scan against a local directory and archive a structured report:

```bash
node dolphin-patrol.js --local <directory>
```

Example:

```bash
node dolphin-patrol.js --local D:/your-project/src
```

### 2. Remote patrol (`--patrol`)

Dispatch the scan command to a remote host over SSH, collect the result, and archive it locally — the complete patrol loop.

**Register a host first** (see `test-ssh-hosts.js` for a ready-to-edit template):

```javascript
import { createHostStore } from './dolphin-ssh-core.js'
const store = createHostStore()
store.create({
  alias: 'server01',
  host: '192.168.1.10',
  port: 22,
  user: 'ops',
  auth: { kind: 'password', password: '...' },   // or { kind: 'key', privateKeyPath: '...' }
  tags: ['prod'],
  environment: 'production',
})
```

Then patrol:

```bash
node dolphin-patrol.js --patrol <alias> <remote-directory>
```

Example:

```bash
node dolphin-patrol.js --patrol server01 /srv/app
```

> Each patrol runs: connection health check → detect remote semgrep → dispatch scan → collect JSON → map to structured findings → archive locally.
> If the remote host has no semgrep, Dolphin uploads the scanner to a remote temp directory and executes it there (fallback path).

### 3. Logging and report generation

All results are normalized into the **SecurityFinding** model and archived as JSON:

```
D:\Dolphin\reports\
├── patrol-local-20260831-223652.json      # local scan report
├── patrol-server01-20260901-200652.json   # remote patrol report
└── dolphin-report-*.md / *.json           # reports from dolphin-core
```

Fields: `host` / `file` / `line` / `col` / `severity` / `checkId` / `message` / `remediationHint` / `metadata`.

### 4. Other entry points

```bash
node dolphin-patrol.js                     # self-test (25 assertions; 3 skipped if semgrep is absent)
node dolphin-core.js --mock [directory]    # dry-run the full pipeline with mock data (no semgrep needed)
node dolphin-ssh-core.js                   # SSH engine self-test (18 assertions)
node test-ssh-hosts.js                     # test host store + health-check failure path
node test-ssh-hosts.js --live              # spin up a local ssh2 server and verify the full patrol loop
```

---

## Architecture

Dolphin is built on three layers — the eyes, the hands, and the brain:

| Layer | File | Responsibility |
|---|---|---|
| **Scanning layer (eyes)** | `dolphin-core.js` | Semgrep wrapper; defines the unified `SecurityFinding` model |
| **Execution layer (hands)** | `dolphin-ssh-core.js` | Standalone SSH engine adapted from the Apache-2.0 licensed dsh-ssh; `exec` / `cluster` / `upload` / `download` / `test` |
| **Controller (brain)** | `dolphin-patrol.js` | Dispatches scans over SSH, collects JSON, structures and archives results |

---

## 🔐 Remote Provisioning Hardening (Safe Deployment)

> Remote tool provisioning has been fully reworked: **the plugin provisions remote semgrep exclusively via isolation techniques (pipx / venv / portable wheel bundle) and never pollutes the production system.**
> `sudo`, `pip install --break-system-packages`, and any write to system site-packages are **strictly forbidden** —
> every deployment command passes a hard gate (`assertNoPrivilegeEscalation`) before leaving the local machine.
> Change note: the legacy "upload a node script" fallback has been removed and replaced by the three-tier isolated provisioning chain below.

When semgrep is missing from the target host's PATH, the patrol provisions it automatically in this priority
order (each step prints a pre-flight verdict: strategy, bytes to upload, estimated remote download, risk level):

| Priority | Strategy | Isolation | Cost |
|---|---|---|---|
| 1 | **pipx** | `pipx install semgrep` into the user-level sandbox (`~/.local/share/pipx`), persistent & reusable | ≈30MB pulled from PyPI on the remote |
| 2 | **Temp venv** | `pip install semgrep` inside `/tmp/dolphin-venv-<ts>`; fully isolated | Same download; ≈30s venv build |
| 3 | **Portable bundle (final fallback)** | Locally cached Linux wheels (≈40–60MB) uploaded via SFTP, then offline-installed with `pip --no-index --target` into an isolated `/tmp` dir (zipfile extraction + `PYTHONPATH` if pip is absent) | SFTP upload traffic (byte count shown in pre-flight) |

- **Auto cleanup**: temp venv, portable bundle and uploaded rules files (`/tmp/dolphin-*`) are `rm -rf`ed right after
  the scan. The **local** wheel cache is kept for reuse (override with `DOLPHIN_SEMGREP_CACHE`, default
  `~/.dolphin/semgrep-wheel-cache`).
- **Honest degradation**: if the remote has neither pipx nor python3, the patrol fails explicitly with a reason —
  it will never silently fall back to privileged operations.
- The cached semgrep version is pinned at first download; clear the cache directory to upgrade.

---

## Programmatic usage

```javascript
import { runPatrol, runLocalScan, buildRemoteScanCommand } from 'dolphin-security'

// Local scan
const local = await runLocalScan('/path/to/project')
console.log(local.summary)   // { ERROR: 3, WARNING: 1, INFO: 0 }

// Remote patrol
const result = await runPatrol('server01', '/srv/app')
if (result.ok) console.log(result.reportFile)

// Build a remote scan command (pure function)
buildRemoteScanCommand('/srv/app', 'p/security-audit')
// → semgrep scan --config p/security-audit /srv/app --json
```

> When running `runPatrol` with an engine you created yourself, remember to call `engine.dispose()` when done — the engine holds a connection pool and keepalive timers that keep the Node event loop alive.

---

## Open source licenses

| Project | License | Usage |
|---|---|---|
| dsh-code-scan | MIT | Semgrep scanning wrapper, base scanning module |
| dsh-plugin-hos-forge-v2 | MIT | Reference for MCP orchestration |
| dsh-web (dsh-ssh subpackage) | Apache-2.0 | SSH/SFTP capabilities, independently packaged as `dolphin-ssh-core.js` |
| ssh2 | MIT | Underlying SSH protocol library |
| semgrep | LGPL-2.1 | Open-source static analysis engine |

Dolphin itself is released under the **MIT** license.

---

## Documentation

- [CHANGELOG.md](./CHANGELOG.md) — **Changelog**
- [README.md](./README.md) — 简体中文
- [WINDOWS_PREVIEW_GUIDE.md](./WINDOWS_PREVIEW_GUIDE.md) — Windows preview setup guide
- [DEVELOPMENT_LOG.md](./DEVELOPMENT_LOG.md) — Development log and pitfalls
- [docs/SSH_RECON_REPORT.md](./docs/SSH_RECON_REPORT.md) — dsh-ssh source recon report

---

## FAQ (Frequently Asked Questions) & Troubleshooting

### pnpm errors while installing a DSH plugin

**Error symptom** (may appear when installing via `dsh plugin --profile web add dsh-dolphin-security` under `D:\DSH`):

```
[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: ssh2@1.17.0, cpu-features@0.0.10
dsh: pnpm failed in profile directory D:\DSH\profiles\web
```

**Root cause**: for security reasons, pnpm refuses to run build scripts of dependencies by default. It therefore blocks `ssh2` and `cpu-features` from compiling, making pnpm exit with a non-zero status so dsh treats the plugin install as failed (the dependency is written but the bundle is never registered).

**Fix**: `cd` into the DSH profile directory (e.g. `D:\DSH\profiles\web` — the directory that holds `pnpm-workspace.yaml`) and run:

```bash
pnpm approve-builds --all
```

This approves all pending build scripts (`ssh2`, `cpu-features`) and sets `allowBuilds` to `true` in `pnpm-workspace.yaml`. Drop `--all` for the interactive picker if you want to approve packages one by one.

If `pnpm approve-builds` is unavailable, manually edit `pnpm-workspace.yaml` in that directory and replace the placeholder values with `true`:

```yaml
allowBuilds:
  cpu-features: true
  ssh2: true
```

Then re-run the plugin install (`dsh plugin --profile web add dsh-dolphin-security`); verify the mount node appears in the config tree with `dsh --profile web --dump-config`.

---

## License

Released under [MIT](./LICENSE). Use legally, compliantly, and only with proper authorization.
