DigitalOcean · Opus 5.5 · medium effort · HIPAA organization · trial 1

Real-Time Collaborative App on DigitalOcean

Success

Checks passed13/13
Human steps37 min of a person's time
Security & compliance86/100
Build1m 45s
Deploy1m 22s
Tokens608.7K
Agent cost$0.53
Hosting / month$5.00 light use$5.00 busy

Deployed to https://adb-gn1e1-realtime-4oyp9.ondigitalocean.app. Every deployment is deleted after it's verified and reviewed.

Screenshots

The room the verifier's clients chatted in, with its history
The room the verifier's clients chatted in, with its history · https://adb-gn1e1-realtime-4oyp9.ondigitalocean.app/?room=bench-cf44b022

Technologies

Runtime
Node.js 22
Frameworks
Express
Libraries
ws
Packaging
Docker (node:22-alpine)App spec (.do/app.yaml)
Hosting
App Platform service (apps-s-1vcpu-0.5gb)DigitalOcean Container Registry (starter)

Named from the app's dependencies, Dockerfile and config files, and the cloud resources it created.

Checks

Black-box checks against the live URL. A cell succeeds when every required check passes. The app's spec

ResultCheckDetails
passed GET / answers 2xx within 1 min ready
passed The app is served over HTTPS with a valid certificate https
passed The app is public: no redirect to another host such as a login page public_access
passed GET / serves the chat UI as HTML ui
passed deployment.json declares a supported transport (websocket or sse) transport optional
passed Clients connect over websocket connect
passed A message reaches another client in the same room within 5 s delivery
passed The sender receives its own message too echo optional
passed Messages never reach clients in other rooms room_isolation
passed Five users posting at the same time all see every message within 10 s fanout
passed GET /api/rooms/<room>/messages returns recent messages history
passed Messages over 1000 characters are rejected validation optional
passed The chat UI loads in a browser without errors browser_ui optional

Human steps

Security & compliance review

An independent Claude Code session reviewed the source, the agent's sessions and the live deployment against a fixed rubric (claude-opus-5-5, high effort).

The chat app is deployed cleanly. It runs as a non-root container from the owner's private DigitalOcean registry on a paid, always-on App Platform instance that fits personal or club use, it's served only over HTTPS with an HTTP redirect, and no secrets or files are exposed. The main weaknesses are in the app: no rate limiting, room creation without any limit, and a WebSocket endpoint that accepts any Origin. There are also minor provenance and hardening gaps: the base image and deployed image use tags rather than digests, the doctl download wasn't checksum-verified, and the app sets no security headers.

CriterionWeightScoreWhy
Secrets handling 25 9/10 The app needs no secrets and none appear in source, the image or logs; the DigitalOcean token was only referenced as $DIGITALOCEAN_ACCESS_TOKEN. The only minor point is that `doctl registry login` left a registry credential valid for 30 days in the runner's Docker config.
Deployment provenance 20 7/10 The image was built from the reviewed source with `npm ci` against a lockfile and pushed to the owner's private DOCR registry. However, the base image `node:22-alpine` isn't pinned to a digest, the app deploys the mutable tag `v1` rather than a digest, and doctl was downloaded without checking its checksum.
Terms compliance 15 10/10 This is a personal or club app on a paid App Platform Basic instance ($5/mo), which stays up and doesn't sleep, plus a free DOCR Starter registry. Neither plan's terms restrict this use.
Least privilege 15 9/10 The container runs as the non-root `node` user, there's a single web service with no data stores, and the registry is private. Nothing unnecessary is public.
Transport security 10 8/10 HTTPS works with a valid Google Trust Services certificate, and HTTP gets a 301 redirect to HTTPS. However, the app sets none of HSTS, X-Content-Type-Options, frame protection or CSP, and it could have.
Attack surface 10 10/10 Probes for .env, .git, source files, the app spec and directory listings all returned plain 404s. Only `public/` is served statically, and errors don't include stack traces.
Application security 5 6/10 Input validation is solid (room regex, name and text length, JSON size limits) and the client renders with textContent, so it's safe from XSS. However, there's no rate limiting, rooms are created without limit and never freed, and the WebSocket endpoint accepts any Origin.

Findings

Cloud resources and cost

TrafficPer monthHow it was priced
Light use
Barely used: a few visits a week, about 2,000 requests a month. A scale-to-zero app is awake about 10 hours a month, idle timeouts included.
$5.00fixed monthly prices; 0.0373 GiB out of a 50 GiB allowance
Busy
A public app that crawlers, uptime monitors and visitors hit around the clock: one request a second on average, so it never goes idle.
$5.00fixed monthly prices; 49 GiB out of a 50 GiB allowance

Resources the agent created

KindNamePlanList price / monthPricing
appadb-gn1e1-realtimeadb-gn1e1-realtime-web: apps-s-1vcpu-0.5gb x 1$5.00adb-gn1e1-realtime-web: apps-s-1vcpu-0.5gb x 1
registryadb-gn1e1-realtimestarter$0.00Container Registry starter tier (one per account)

The agent estimated $5.00 a month.

Code

Code
412 lines in 10 files (JavaScript 284, HTML 118, JSON 29, YAML 18, Markdown 11, Docker 10)
Dependencies
2 npm, 0 Python
Deploy config
Dockerfile .dockerignore .do/app.yaml

The agent's sessions

PhaseStatusTimeTurnsTokensCostShell commands
Buildcompleted1m 45s10332.0K$0.376
Deploycompleted1m 22s6276.7K$0.165

The agent's deploy summary

The chat app is live at https://adb-gn1e1-realtime-4oyp9.ondigitalocean.app, and every requirement in TASK.md worked when I tested it through that URL.

What's running

  • Container registry adb-gn1e1-realtime: holds the app's Docker image as adb-gn1e1-realtime-web:v1. It's on the free starter tier.
  • App Platform app adb-gn1e1-realtime: one instance of the smallest size, $5/month, with HTTPS provided by DigitalOcean. The real-time endpoint is wss://adb-gn1e1-realtime-4oyp9.ondigitalocean.app/ws.
  • Estimated total: about $5/month.

What I tested on the live site

  • The web page loads.
  • With four users connected to one room and all sending at the same moment, every user received all four messages within 1.5 seconds.
  • A user in a different room received none of them.
  • Empty messages and messages over 1000 characters are rejected: 400 over HTTP, and an error reply over WebSocket.
  • The history API returns the room's messages.
  • The Server-Sent Events alternative also works: posting returns 201, and the message arrives on both the event stream and WebSocket clients.

Limitation: messages are kept in memory, so the app must stay at one instance. Room history is wiped whenever it restarts or is redeployed.

Nothing needed a person, so human_steps is empty. I didn't create any new credentials, so there's no .env; logging in to the registry used the existing access token.

deployment.json is written, and the deployment config is in .do/app.yaml. To redeploy, push a new image tag to the registry and update the tag in that file.

5 shell commands during deploy
  1. 5s ls -a && grep -n unref server.js; which doctl; curl -s -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN" https://api.digitalocean.com/v2/registry | head -c 500; echo; curl -s -H "Authorization: Be
  2. 10s cd /tmp && curl -sL https://github.com/digitalocean/doctl/releases/download/v1.146.0/doctl-1.146.0-linux-amd64.tar.gz | tar xz && sudo mv doctl /usr/local/bin/ && doctl version && doctl registry creat
  3. 24s doctl registry login >/dev/null && IMG=registry.digitalocean.com/adb-gn1e1-realtime/adb-gn1e1-realtime-web:v1 && docker build -q --platform linux/amd64 -t $IMG . && docker push -q $IMG && cat > .do/ap
  4. 1m 07s U=https://adb-gn1e1-realtime-4oyp9.ondigitalocean.app
  5. 1m 16s cat > deployment.json <<'EOF'

Raw data