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
Binary file added assets/joachimjordan.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/lukeroy.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions content/authors/joachimjordan/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: "Joachim Jordan"
text: "Tech Lead Code Engine Platform @ IBM Cloud"
---

Welcome to my blog post feed.
4 changes: 2 additions & 2 deletions content/authors/lukeroy/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "Luke Roy"
text: "Cloud Sofware Engineer @ IBM Cloud Code Engine"
text: "Cloud Software Engineer @ IBM Cloud Code Engine"
---

Welcome to my blog post feed.
Welcome to my blog post feed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
271 changes: 271 additions & 0 deletions content/posts/remote-bob-run-bob-shell-in-the-cloud/index.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions data/authors/joachimjordan.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name = "Joachim Jordan"
bio = "Tech Lead Code Engine Platform @ IBM Cloud"
image = "joachimjordan.jpg"

# Add external links (this will automatically generate clickable icons under the author name)
[links]
5 changes: 5 additions & 0 deletions data/authors/josip-ledic.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = "Josip Ledic"
bio = "Software Engineer @ IBM Cloud Code Engine"

# Add external links (this will automatically generate clickable icons under the author name)
[links]
8 changes: 8 additions & 0 deletions data/authors/lukeroy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name = "Luke Roy"
bio = "Cloud Software Engineer @ IBM Cloud Code Engine"
image = "lukeroy.jpg"

# Add external links (this will automatically generate clickable icons under the author name)
[links]
linkedin = "https://www.linkedin.com/in/luke-roy"
github = "https://github.com/lukeroy"
24 changes: 24 additions & 0 deletions remote-bob/.ceignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# CE source-upload ignore rules for the job-agent build context.
# The job-agent Dockerfile only needs job-agent/ — exclude everything else.

# Secrets and local config
.env
.env.template

# Other service source (not needed for job-agent build)
apiserver/

# Static browser client (not needed in the container)
browser-client/

# Launcher script and docs
remote-bob
README.md
.gitignore
.ceignore

# Runtime scratch and caches
tmp/
bobshell-*.tgz
*.log
.DS_Store
55 changes: 55 additions & 0 deletions remote-bob/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Remote Bob — Configuration Template
# Copy this file to .env and fill in the three required keys.
#
# Workflow:
# cp .env.template .env
# # edit .env — set the three required keys below
# ./remote-bob --setup # first time: provision infra + build images
# ./remote-bob --new-session # start a job run and open the browser
# ./remote-bob --connect # reopen the browser (session still running)
# ./remote-bob --end-session # kill the job run (infra stays)
# ./remote-bob --clean # remove all IBM Cloud resources
# ./remote-bob # show current status

# ─── Required ────────────────────────────────────────────────────────────────

# Bob Shell API key — get from https://bob.ibm.com (Settings → API Keys)
BOBSHELL_API_KEY=your-bob-shell-api-key-here

# Basic-auth password shown in the browser login prompt
GATEWAY_PASSWORD=your-gateway-password-here

# IBM Cloud API key with Code Engine and Container Registry permissions
IBMCLOUD_API_KEY=your-ibmcloud-api-key-here

# ─── Optional overrides (defaults shown) ─────────────────────────────────────

# IBM Cloud region
# CE_REGION=us-east

# Code Engine project (created if it does not exist)
# CE_PROJECT=remote-bob--ce-project

# IBM Cloud resource group (created if it does not exist)
# RESOURCE_GROUP=remote-bob--rg

# CE app name for the apiserver
# APISERVER_APP_NAME=remote-bob-apiserver

# CE job name for the job-agent
# JOB_NAME=remote-bob-job-agent

# Job-agent run resources
# DEFAULT_CPU=1
# DEFAULT_MEMORY=2G
# DEFAULT_TIMEOUT=86400

# Path to Chrome binary (auto-detected on macOS and Linux if not set)
# CHROME_BIN=

# Chrome remote-debugging port (CDP / E2E tooling)
# CHROME_DEBUG_PORT=

# HMAC signing key for run tokens — generated fresh in-memory each run.
# Set only if you need token stability across apiserver restarts.
# ENCRYPTION_KEY=
27 changes: 27 additions & 0 deletions remote-bob/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ── Secrets & local config ───────────────────────────────────────────────────
# .env holds real credentials. Never commit it; only .env.template is tracked.
.env

# ── Go build artefacts ───────────────────────────────────────────────────────
# Compiled binaries produced by `go build`.
apiserver/apiserver
job-agent/job-agent

# Go vendor directories (populated by `go mod vendor`).
apiserver/vendor/
job-agent/vendor/

# ── Bob Shell package cache ──────────────────────────────────────────────────
# run.sh downloads and caches the Bob Shell tarball here before passing it
# to the job-agent Docker build via --build-arg BOBSHELL_TARBALL.
bobshell-*.tgz

# ── Runtime scratch directories ──────────────────────────────────────────────
# Chrome user-data dirs created by run.sh for local CDP / E2E sessions.
tmp/

# ── Logs ─────────────────────────────────────────────────────────────────────
*.log

# ── OS cruft ─────────────────────────────────────────────────────────────────
.DS_Store
147 changes: 147 additions & 0 deletions remote-bob/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Remote Bob

Remote Bob gives you a **full Bob Shell terminal running in IBM Cloud Code Engine**, accessible from your local browser. One command provisions the infrastructure; a second command opens the terminal. Close the browser — the session keeps running in the cloud. Open it again with a single command.

---

## Prerequisites

| Requirement | Notes |
|---|---|
| **IBM Cloud account** | With permission to create Code Engine projects and Container Registry namespaces |
| **IBM Cloud API key** | Needs Code Engine Writer + Container Registry Writer roles |
| **Bob Shell API key** | Get from [bob.ibm.com](https://bob.ibm.com) → Settings → API Keys |
| **`ibmcloud` CLI** | [Install](https://cloud.ibm.com/docs/cli) — the `code-engine` plugin is installed/updated automatically |
| **`jq`** | `brew install jq` / `apt install jq` |
| **`curl`**, **`openssl`** | Included on macOS and most Linux distros |
| **Google Chrome** | Auto-detected on macOS (`/Applications/Google Chrome.app`) and Linux (`google-chrome`) |

---

## Quickstart

```bash
# 1. Copy the config template and fill in your three keys
cp .env.template .env
# BOBSHELL_API_KEY=...
# GATEWAY_PASSWORD=choose-any-password
# IBMCLOUD_API_KEY=...

# 2. Provision IBM Cloud resources and build container images (~20 min first time)
./remote-bob --setup

# 3. Start a session — opens a Chrome terminal window
./remote-bob --new-session

# 4. Close the browser window when done. The session keeps running in the cloud.

# 5. Reopen the browser for the same running session
./remote-bob --connect

# 6. End the session (stops the job run; infrastructure stays for fast restart)
./remote-bob --end-session

# 7. Start another session without rebuilding
./remote-bob --new-session

# 8. Remove all IBM Cloud resources when finished
./remote-bob --clean

# Check current status at any time
./remote-bob
```

---

## Command reference

| Command | What it does |
|---|---|
| `--setup` | Provisions IBM Cloud resources (resource group, CE project, secrets) and builds the apiserver and job-agent container images. **Idempotent** — safe to re-run after code changes. |
| `--new-session` | Submits a new job run, waits for the agent to connect, and opens Chrome. Requires `--setup` to have completed. Prevents starting a second session if one is already live. |
| `--connect` | Queries IBM Cloud for the live session and reopens the Chrome terminal. No re-provisioning. |
| `--end-session` | Gracefully disconnects the agent and deletes all job runs. Leaves the app and job definition in place so the next `--new-session` starts in seconds. |
| `--clean` | Deletes all provisioned IBM Cloud resources: job runs, job, app, secrets, CE project, resource group. |
| *(no args)* | Logs in and prints current infrastructure + session status with a suggested next command. |

All commands accept `--config=FILE` to use a config file other than `.env`.

---

## Configuration

Copy `.env.template` to `.env`. Only the three required keys need to be set:

```bash
# Required
BOBSHELL_API_KEY=your-bob-shell-api-key
GATEWAY_PASSWORD=any-password-you-choose
IBMCLOUD_API_KEY=your-ibm-cloud-api-key
```

Everything else has sensible defaults (region `us-east`, auto-generated `ENCRYPTION_KEY`, etc.). See `.env.template` for the full list of optional settings such as `BOB_MODE`, `DEFAULT_CPU`, `DEFAULT_MEMORY`, and `CHROME_BIN`.

**The `.env` file is never modified at runtime.** Session state (app URL, agent ID) is retrieved live from IBM Cloud on every invocation.

---

## How it works

```
Browser (Chrome, file:// page, xterm.js)
│ WebSocket /ws/browser?token=<wsToken>&agent=<id>&service=ttyd
Apiserver (Go, IBM Code Engine app, scales to zero)
│ auth: POST /auth/login → 60s WS token
│ POST /auth/runs → per-run agent token (HMAC-signed)
│ relay: opaque frame proxy — text + binary frames preserved verbatim
│ WebSocket /ws/agent (Bearer <runToken>)
Job-agent (Go, IBM Code Engine job run)
│ dials apiserver on startup, registers services
│ opens upstream ttyd connection per relay request
ttyd → tmux → Bob Shell
```

**Apiserver** is a thin authenticated relay deployed as a Code Engine application. It holds an in-memory agent registry, issues short-lived tokens, and proxies WebSocket frames between the browser and the job-agent without inspecting the payload. It has no database and no persistence; it shuts itself down when the last agent disconnects.

**Job-agent** is a Go binary deployed as a Code Engine job run. On startup it dials the apiserver control WebSocket, registers the `ttyd` service, and handles relay connections by piping raw frames between the apiserver and a local `ttyd` process. It runs `tmux` → Bob Shell inside `ttyd` and serves a health endpoint for the job run lifecycle. An idle timeout shuts it down automatically when not in use.

**Browser client** is a single self-contained HTML file loaded from `file://`. It authenticates with the gateway password, opens a WebSocket relay, and renders the terminal using xterm.js. No server-side rendering, no CDN dependencies.

**Secrets** are stored in two IBM Code Engine secrets injected as environment variables:
- `remote-bob-gateway` — `GATEWAY_PASSWORD`, `ENCRYPTION_KEY`
- `remote-bob-bobshell` — `BOBSHELL_API_KEY`

---

## Repository layout

```
remote-bob/
├── apiserver/ # Go apiserver — auth, registry, relay
│ ├── cmd/apiserver/
│ ├── internal/
│ ├── Dockerfile
│ └── go.mod
├── job-agent/ # Go job-agent — tunnel daemon, ttyd, tmux, Bob Shell
│ ├── cmd/job-agent/
│ ├── internal/tunnel/
│ ├── Dockerfile
│ └── go.mod
├── browser-client/ # Static xterm.js terminal page (file://)
│ └── single-session.html
├── remote-bob # Launcher — all commands
├── .env.template # Config template
└── README.md
```

---

## Building and testing the Go modules

```bash
cd remote-bob/apiserver && go build ./... && go test ./...
cd remote-bob/job-agent && go build ./... && go test ./...
```
6 changes: 6 additions & 0 deletions remote-bob/apiserver/.ceignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# CE source-upload ignore rules for the apiserver build context.
# --build-source points to remote-bob/apiserver/ — this file lives there.
# Dependencies are fetched by `go mod download` inside the build.
.env*
*.log
tmp/
7 changes: 7 additions & 0 deletions remote-bob/apiserver/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# apiserver build context — Code Engine source builds upload this directory.
# Exclude the built binary (rebuilt in the image), env/template files, and
# local cruft. Dependencies are fetched by `go mod download` inside the build.
apiserver
.env*
*.log
tmp/
22 changes: 22 additions & 0 deletions remote-bob/apiserver/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Stage 1: build
FROM quay.io/projectquay/golang:1.26 AS build
USER root
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /apiserver ./cmd/apiserver

# Stage 2: runtime
FROM registry.access.redhat.com/ubi9/ubi-minimal:latest
RUN microdnf install -y ca-certificates && microdnf clean all

# Create non-root user
RUN useradd -m -u 1001 appuser

COPY --from=build --chown=appuser:appuser /apiserver /apiserver

EXPOSE 8080

USER 1001
ENTRYPOINT ["/apiserver"]
Loading
Loading