digitalocean/ShellPort

JavaScript

Open original ↗

Captured source

source ↗
published Mar 26, 2026seen 5dcaptured 15hhttp 200method plain

digitalocean/ShellPort

Description: Ephemeral Coding Interview Workstation

Language: JavaScript

Stars: 0

Forks: 0

Open issues: 0

Created: 2026-03-26T19:30:33Z

Pushed: 2026-06-09T04:15:18Z

Default branch: main

Fork: no

Archived: no

README:

ShellPort

Ephemeral coding interview workstation. One command to install, a local browser dashboard to run it, one click to remove.

---

Install

Two entry points, same installer — admins set up company-owned machines, candidates set up their own.

Admin (company-owned machine):

# macOS / Linux
curl -fsSL https://do.co/shellport-admin-mac | bash
# Windows (PowerShell)
irm https://do.co/shellport-admin-win | iex

Candidate (own machine):

# macOS / Linux
curl -fsSL https://do.co/shellport-macos | bash
# Windows (PowerShell)
irm https://do.co/shellport-windows | iex

Prerequisites: Docker (running) and Node.js. Your browser opens to http://localhost:3000 — everything runs locally, no cloud. The dashboard shows build progress, then "Start in" buttons for each detected editor (VS Code, Cursor, Windsurf, VSCodium…), the web editors vscode.dev and github.dev, and the container terminal.

Deploy via MDM (Jamf / Intune)

The same one-liner is the MDM payload — no wrapper needed. ShellPort is per-user (it installs to ~/shellport, uses the logged-in user's Docker, and opens their browser), and the installer detects when an MDM runs it as root (Jamf) or SYSTEM (Intune) and automatically re-runs in the logged-in user's session, forwarding any SHELLPORT_* config.

  • Jamf (macOS): paste curl -fsSL https://do.co/shellport-admin-mac | bash into a script and run it from a policy. Use a login or Self Service trigger so a user is present; if none is, the run exits cleanly so the next login retries. Set per-event config (questions, Slack token/channel, label) as policy parameters exported as SHELLPORT_*, or bake them into the release.
  • Intune (Windows): deploy irm https://do.co/shellport-admin-win | iex as a platform script. Either set "Run this script using the logged-on credentials = Yes" (cleanest — runs as the user directly), or leave it as SYSTEM and the installer re-launches into the user's session via a one-shot scheduled task.

Prerequisites still apply per user: Docker (set to start at login) and Node.js must be installed for the logged-in user, or the installer stops with a clear message.

---

The Container

The IDE opens inside an isolated container with the latest Go, Python, Java, Node.js, C/C++, TypeScript, GitHub Copilot, Claude Code, GitHub CLI, doctl, Homebrew, neovim, jq, and yq. All candidate work must be saved in /workspaces.

---

Cleanup

Click "End Interview" in the dashboard, or run the script directly:

  • macOS / Linux: ~/shellport/done.sh
  • Windows: ~\shellport\Done.ps1

This stops the server, kills IDE processes, tears down ShellPort's own container and volume, and deletes the project directory. It is scoped to ShellPort — never a host-wide Docker prune, and it leaves browsers and credentials untouched.

Recycle vs. End Event (operator)

Two operator actions, both gated behind OS-level admin auth (macOS/Linux sudo/pkexec, Windows UAC) so a candidate session can't reach them:

  • Recycle (DO station): scrub the host and load a fresh question for the next candidate without rebuilding the machine.
  • End Event: tear down the workstation — power off a DO station, or return the uninstall command on a BYOD machine.

ShellPort detects its machine type. On a candidate's own (BYOD) machine it only ever removes its own footprint — never the aggressive host scrub reserved for dedicated DO stations.

Containment leak (managed stations only): candidate work belongs in the container's /workspaces volume, which the teardown destroys. If a candidate saves to the host instead (Desktop, Documents, Downloads), the Recycle/End Event scrub diffs those folders against the pre-session snapshot and removes only the files added during the session — pre-existing station files are left untouched. The reset screen flags how many leaked files were found/removed, and the run writes .last_scrub.json (baseline, removed, and any that couldn't be removed). Verify it with:

# macOS / Linux
node ~/shellport/admin/validate-containment-leak.js
# Windows
node $env:USERPROFILE\shellport\admin\validate-containment-leak.js

The validator confirms every removed file is gone, every pre-existing file survived, and no candidate-added file remains — exiting non-zero if anything is off. This runs only on managed DO stations (never BYOD), and never touches files outside the candidate's own work folders.

---

Security

Credential isolation is enforced via devcontainer.json: IDE settings block GitHub token injection, Git credential forwarding, SSH agent forwarding, and port forwarding; every spawned shell force-clears host tokens; the remote environment nullifies host variables and suppresses history. The container mounts only a named Docker volume — no host filesystem, Docker socket, or SSH agent socket is exposed.

Interviewer surfaces — Settings, telemetry, Recycle, End Event — are gated behind an admin unlock (the machine's OS-user password; no separate admin password) and never appear on a BYOD machine. Before each interview ShellPort confirms the host is clean and holds setup until any residue is cleared.

The troubleshooting panel (common fixes plus the manual fallback) is always available to a candidate on their own BYOD machine so they can recover unaided — destructive commands carry a warning and a confirm. On a managed DO station it is gated behind the same admin unlock, so a candidate session can't reach teardown/remove commands.

---

Optional Features

Off by default. Enable via .env or a config URL.

| Feature | .env variable | What it does | |---|---|---| | Timer | ENABLE_TIMER=true | Live active/idle countdown. On expiry: NOTIFY, LOCK, or WIPE. Idle defined by INACTIVITY_TIMEOUT_MINUTES. | | Telemetry | ENABLE_TELEMETRY=true | Exports shell history, AI usage, and Git activity on cleanup. | | Questions | QUESTIONS_URL=… | Loads the assigned question during setup. Source is a Google Sheet of [title, docId] rows (QUESTION_ROW pins the row) or a Google Doc with one question per tab — all tabs are detected automatically and one is assigned…

Excerpt shown — open the source for the full document.

Notability

notability 5.0/10

New repo from notable company, lacking traction data