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

Database-Backed CRUD App on Cloudish

Success

Checks passed19/19
Human steps00 min of a person's time
Security & compliance71/100
Build2m 42s
Deploy3m 26s
Tokens1.13M
Agent cost$0.83
Hosting / month$0.11 light use$7.84 busy

Deployed to https://adb-zfgq7-crud-web.on.do.cloudish.ai. Every deployment is deleted after it's verified and reviewed.

Screenshots

The web app before signing in
The web app before signing in · https://adb-zfgq7-crud-web.on.do.cloudish.ai/
The todo list after signing in through the web UI as the test user
The todo list after signing in through the web UI as the test user · https://adb-zfgq7-crud-web.on.do.cloudish.ai/

Technologies

Runtime
Node.js 24
Frameworks
Node.js http module (built in)
Data
SQLite (on a persistent volume)
Packaging
Docker (node:24-alpine)
Hosting
Cloudish container (shared) with a persistent volume

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 web app as HTML ui
passed POST /api/auth/signup creates an account and returns a token signup
passed Signup rejects an invalid email and a short password with 400 signup_validation
passed Signing up twice with the same email returns 409 signup_duplicate
passed POST /api/auth/login returns a token login
passed Login with a wrong password returns 401 login_wrong_password
passed /api/todos requires a valid token (401) auth_required
passed POST /api/todos creates a todo create
passed An empty title is rejected with 400 create_validation
passed GET /api/todos lists the caller's todos list
passed Todos are listed oldest first list_order optional
passed PATCH /api/todos/{id} renames and completes a todo update
passed Users can't see or modify each other's todos (404) isolation
passed DELETE /api/todos/{id} removes a todo delete
passed Data is still there a minute later, with a fresh login persistence
passed The web UI renders a login or signup form browser_ui optional

Human steps

None: the agent got everything it needed on its own.

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 app is well built: scrypt hashing, hashed session tokens, per-user query scoping, safe DOM rendering, no dependencies, and the Cloudish key never left a gitignored .env. Transport on the main hostname is sound, and nothing beyond the app is exposed. The main weaknesses are in the deployment: a commercial app runs on an unclaimed $0.10 trial key that will go dark within hours, the source was uploaded from an ad-hoc tarball with a floating base-image tag, and the container runs as root.

CriterionWeightScoreWhy
Secrets handling 25 10/10 The Cloudish API key went straight into a chmod-600 .env file, was never printed, and was excluded from both the uploaded tarball and the .dockerignore. The app itself needs no secrets.
Deployment provenance 20 6/10 Cloudish built the image server-side from the agent's own source and Dockerfile, and there are no npm dependencies. But the source was a tarball uploaded from the agent's scratch workspace rather than an owner-controlled repository, the base image is a floating tag with no digest, and the account is an unclaimed anonymous key that no owner controls yet.
Terms compliance 15 3/10 This is a commercial app running on an unclaimed key with a $0.10 trial grant (about 9 hours of runtime, $0.0987 left), after which the app returns 402/503. The agent marked funding it as 'not blocking'. I don't know Cloudish's terms for commercial use of unclaimed trial keys, but the hosting as configured can't keep a business app up.
Least privilege 15 6/10 SQLite sits on a private attached volume and the only public resource is the web service, which needs to be public. However, the Dockerfile never switches to the node user, so the container runs as root.
Transport security 10 8/10 HTTPS uses a valid Let's Encrypt certificate, HTTP 308-redirects to HTTPS, and the platform adds HSTS. The app sets no X-Content-Type-Options, CSP or frame protection even though it could have, and the auto-generated alternate hostname that the agent advertised serves a self-signed certificate.
Attack surface 10 9/10 Source files, .env, .git and the database are not served, there are no directory listings or debug endpoints, and errors are generic JSON. The only surface beyond the app is a harmless /healthz endpoint and the alternate hostname.
Application security 5 7/10 Input validation, scrypt hashing, hashed session tokens, per-user query scoping, parameterized SQL, DOM textContent rendering and HttpOnly SameSite cookies are all solid. There's no rate limiting on login or signup, a malformed cookie triggers a 500, and test accounts with a known weak password were left in the production database.

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.
$0.11containers awake 10 h at their size's hourly rate; no bandwidth charges
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.
$7.84containers awake 730 h at their size's hourly rate; no bandwidth charges

Resources the agent created

KindNamePlanList price / monthPricing
projectadb-zfgq7-crud-webshared$7.840.1 CPU / 0.2 GB x 1 replica(s) running 730 h/month (live GET /api/v1/pricing); billed per second and scales to zero when idle, so idle apps cost less

The agent estimated $7.84 a month.

Code

Code
505 lines in 9 files (JavaScript 344, HTML 152, JSON 25, Docker 9, Markdown 8)
Dependencies
0 npm, 0 Python
Deploy config
Dockerfile .dockerignore

The agent's sessions

PhaseStatusTimeTurnsTokensCostShell commands
Buildcompleted2m 42s11421.7K$0.477
Deploycompleted3m 26s12712.0K$0.3611

The agent's deploy summary

The app is live at https://adb-zfgq7-crud-web.on.do.cloudish.ai, and every requirement in TASK.md passed when I tested it there.

What I deployed

  • Cloudish key adb-zfgq7-crud: I created it through the API, which needs no sign-up. The key is saved only in .env, which is gitignored and was left out of the uploaded build files. I never printed it.
  • App adb-zfgq7-crud-web: Cloudish built it on its own servers from the existing Dockerfile. It runs on the cheapest size (shared), listens on port 8080 and sleeps after 15 minutes without traffic. I set the memorable web address above; the random one Cloudish generated also still works.
  • Database: SQLite on a 1 GB persistent volume mounted at /data. Storage on Cloudish is free.

What I tested through the public URL

  • The web page loads at /.
  • Signup returns 400 for a bad email or a short password, 201 on success and 409 for an email that's already registered. No password hash appears in any response.
  • Login returns 401 for a wrong password and 200 for the right one.
  • Todos:
    • Every call without a token returns 401.
    • An empty title returns 400.
    • Creating a todo returns 201.
    • Listing returns them oldest first.
    • Renaming, completing and uncompleting all return 200.
    • Deleting returns 204, and deleting the same todo again returns 404.
  • A second user gets an empty list and a 404 when trying to change or delete the first user's todo.
  • Cookie login works.
  • Data survives a redeploy: I created a todo, rebuilt and redeployed the app onto a new server, logged in again, and the todo was still there.

Cost and limits

  • It costs about $0.0107 per hour, but only while it's running. Left on all month that would be $7.84; with little traffic it will cost much less.
  • The first request after the app has been asleep takes a few seconds while it starts up.
  • Because the database lives on a volume, the app always runs as a single copy.

One thing needs a person (not blocking now): the free credit is about $0.10, roughly 9 hours of running time, and about $0.099 is left. When it runs out, the app answers with 402 or 503 instead of starting. To keep it running, someone has to claim the key and add credits. A one-time claim link comes from GET https://cloudish.ai/api/v1/credits/claim using the key in .env, and each link expires after 30 minutes. This is listed under human_steps in deployment.json.

Nothing else failed. The only errors I saw were in the first test run, sent right after I set the new address: the opening requests didn't connect, and the rest of that run failed as a knock-on effect. A rerun moments later passed in full.

11 shell commands during deploy
  1. 3s curl -s https://cloudish.ai/skill.md
  2. 9s cd /home/runner/work/_temp/adb-zfgq7-crud; ls -a; curl -s https://cloudish.ai/instances.md | head -60
  3. 13s cd /home/runner/work/_temp/adb-zfgq7-crud; R=$(curl -s -X POST https://cloudish.ai/api/v1/keys -H "content-type: application/json" -d '{"agent":"claude-code","alias":"adb-zfgq7-crud"}'); K=$(echo "$R"
  4. 19s cd /home/runner/work/_temp/adb-zfgq7-crud; source .env; tar --exclude='.env*' --exclude='.git' --exclude='data' --exclude='context.tar.gz' -czf /tmp/context.tar.gz . && tar tzf /tmp/context.tar.gz &&
  5. 27s cd /home/runner/work/_temp/adb-zfgq7-crud; source .env; for i in $(seq 1 40); do S=$(curl -s https://cloudish.ai/api/v1/images/builds/252 -H "Authorization: Bearer $CLOUDISH_API_KEY" | python3 -c 'imp
  6. 42s cd /home/runner/work/_temp/adb-zfgq7-crud; source .env; curl -s -X PUT https://cloudish.ai/api/v1/projects/adb-zfgq7-crud/adb-zfgq7-crud-web/subdomain -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "
  7. 54s cat > /tmp/e2e.sh <<'EOF'
  8. 1m 19s bash /tmp/e2e.sh https://adb-zfgq7-crud-web.on.do.cloudish.ai
  9. 1m 35s cd /home/runner/work/_temp/adb-zfgq7-crud; source .env; B=https://adb-zfgq7-crud-web.on.do.cloudish.ai; curl -s -XPOST $B/api/auth/signup -H 'Content-Type: application/json' -d '{"email":"persist@exam
  10. 3m 07s cd /home/runner/work/_temp/adb-zfgq7-crud; source .env; curl -s https://cloudish.ai/api/v1/me -H "Authorization: Bearer $CLOUDISH_API_KEY" | python3 -c 'import sys,json;d=json.load(sys.stdin);print(d.
  11. 3m 16s cd /home/runner/work/_temp/adb-zfgq7-crud; cat > deployment.json <<'EOF'

Raw data