Metadata-Version: 2.4
Name: nullgate
Version: 1.2.4
Summary: Disposable SSH gateway into confined directory workspaces
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: asyncssh==2.24.0
Requires-Dist: cryptography>=39
Requires-Dist: websockets
Dynamic: license-file

# Nullgate

Disposable SSH gateway into confined directory workspaces for remote containers, ephemeral developer boxes, CI nodes, and cloud instances.

## Quick start

Run Nullgate directly from PyPI without installing it first:

```bash
# Share the current directory over the default srv.us provider
uvx nullgate start

# Share a specific workspace
uvx nullgate start /workspace

# Compact form: workspace, SSH port, srv.us slot, provider
uvx nullgate start /workspace 8022 1 -t srvus
```

Then check the endpoint and print the SSH connection setup:

```bash
uvx nullgate status
uvx nullgate connect
```

Nullgate allows connections without credentials by default. Use
`--no-public-access` to require an authorized SSH key or generated password.

## Features

- **Ingress Transports**: Publish endpoints via srv.us reverse tunnels (default), Upterm WebSocket relays, Cloudflare Worker relays, or Cloudflare Argo (`cloudflared`) tunnels.
- **Confinement**: SFTP and SCP workloads are restricted to the designated workspace root; parent traversals and out-of-root symlinks are blocked.
- **Host file visibility**: Relative transfer paths begin in the workspace root while absolute paths address host locations, matching shell behavior; add `--restrict-file-transfer` for strict workspace-only transfers.
- **Direct Shell Access**: Authenticated PTY sessions run interactively under the local user credentials.
- **Synthetic UID Resilience**: Runs seamlessly in container environments missing user records in `/etc/passwd`.
- **Persistent Key Identities**: Host keys and identity seeds persist across restarts rather than being silently regenerated.
- **Safe Process Tracking**: Process launch start times are verified alongside PIDs to prevent signaling recycled processes.

## Installation

Install from the public distribution channel:

```bash
curl -LsSf https://shadowdocks.github.io/nullgate-dist/install.sh | sh
```

The installer downloads the published wheel, verifies its SHA-256 checksum,
and installs it in an isolated `uv` tool environment. The private source
repository is not required on the target machine.

Alternatively, install the published package from PyPI:

```bash
pip install nullgate
```

## Usage

### Start

Launch the gateway service and ingress transport in the background:

```bash
# Default srv.us transport on port 4822 sharing current directory
nullgate start

# Custom path, port, and slot
nullgate start /workspace --ssh-port 4822 --tunnel-slot 1

# The same values in compact positional form
nullgate start /workspace 4822 1

# Select specific transport provider
nullgate start . --provider upterm
nullgate start . --provider srvus
nullgate start . --provider cloudflare --relay-url https://relay.example.com
nullgate start . --provider cloudflared --public-hostname workspace.example.com --cloudflare-token "$TUNNEL_TOKEN"
```

Options:
- `-p`, `--ssh-port`: Local SSH server port.
- `-s`, `--tunnel-slot`: srv.us tunnel slot.
- `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `srvus`.
- `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
- `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
- `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
- `--public-access`: Allow connections without credentials. Enabled by default and unsafe on public endpoints.
- `--no-public-access`: Require authentication.
- `--tcp-forwarding`: Enable SSH TCP tunneling (`ssh -L`).
- `--no-tcp-forwarding`: Disable SSH TCP tunneling.
- `--restrict-file-transfer`: Keep SFTP and SCP inside the workspace.
- `--no-restrict-file-transfer`: Allow host-visible file transfers.

### Status

Display operational status, running PIDs, connection URLs, and security settings:

```bash
nullgate status
```

### Connect

Print client connection strings and OpenSSH client configuration directives:

```bash
nullgate connect
```

### Logs

Stream or print daemon logs:

```bash
nullgate logs
nullgate logs -f
nullgate logs gateway
nullgate logs transport
```

### Stop

Terminate running gateway and transport background processes:

```bash
nullgate stop
```

### Restart

Restart daemon instances reusing active or saved workspace settings:

```bash
nullgate restart
```

### Upgrade

Fetch and install the newest release:

```bash
nullgate upgrade
nullgate upgrade --version 1.0.1
```

Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
remain available as compatibility aliases. Their earlier option names also
remain accepted, but new scripts should use the names documented above.
Unknown flags and their optional values are ignored for compatibility with
external launchers.

## Authentication and Security Boundaries

- **Authentication Baseline**: Public access is enabled by default. Pass `--no-public-access` to require authorized SSH keys from `~/.ssh/authorized_keys` or a high-entropy secret created in the runtime directory.
- **Public access (`--public-access`)**: Bypasses authentication checks entirely; any incoming connection with network access is accepted.
- **Upterm Transport**: Relies on authorized SSH public keys or `--public-access` (Upterm does not support password authentication). The relay itself is trusted for inbound multiplexing.
- **Filesystem Confinement**: SFTP and SCP access cannot escape the designated workspace directory.
- **Host Transfer Mode (default)**: Relative SFTP and SCP paths begin in the workspace directory, while absolute paths refer to host filesystem locations subject to OS user permissions. Pass `--restrict-file-transfer` to limit transfers to the workspace namespace and reject symlink escapes.
- **Interactive Shell Privileges**: Command and terminal sessions execute with the permissions of the host account rather than inside an OS chroot.
- **State Storage**: Daemon PIDs and logs are maintained in `gateway.pid`, `transport.pid`, `gateway.log`, and `transport.log`, with session records kept in `manifest.json` and `settings.json`.

## Environment Variables

| Variable | Description |
|---|---|
| `NULLGATE_PASSWORD` | Gateway-process credential; normally managed internally by `nullgate start` |
| `NULLGATE_STATE_DIR` | Directory holding runtime state and logs (defaults to `~/.local/state/nullgate`) |
| `NULLGATE_IDENTITY_SEED` | Seed value used for deterministic Ed25519 key derivation |
| `NULLGATE_TUNNEL_HOST` | Host address for srv.us ingress (default: `srv.us`) |
| `NULLGATE_TUNNEL_PORT` | Port for srv.us ingress (default: `22`) |
| `NULLGATE_CLOUDFLARED_TOKEN` | Credential token for `cloudflared` tunnels |
| `NULLGATE_CONFINE_SFTP` | Set to `1` to confine SFTP and SCP transfers to the workspace root |
| `NULLGATE_VERSION` | Install a specific published version instead of the stable release; accepts `1.0.1` or `v1.0.1` |
| `NULLGATE_DIST_URL` | Override the public release channel used by `install.sh` |
| `NULLGATE_INSTALL_URL` | Override the installer URL used by `nullgate upgrade` |

## Development

Run internal modules directly:

```bash
# Gateway daemon
python -m nullgate.gateway --root . --port 4822 --accept

# srv.us transport
python -m nullgate.ingress --host srv.us --port 22 --local-port 4822 --slot 1 --key ~/.ssh/id_ed25519

# Cloudflare WebSocket bridge
python -m nullgate.bridge origin wss://relay.example.com/relay/SESSION --port 4822
python -m nullgate.bridge client wss://relay.example.com/relay/SESSION

# Upterm WebSocket client route
python -m nullgate.wsroute client wss://uptermd.upterm.dev/...

# Run test suite
uv run python -m unittest discover -s tests
```

## License

MIT License. See [LICENSE](LICENSE) for details.
