Skip to content

Custom capability plugins + /invoke endpoint#3

Open
amiller wants to merge 13 commits into
mainfrom
feat/custom-plugins-invoke
Open

Custom capability plugins + /invoke endpoint#3
amiller wants to merge 13 commits into
mainfrom
feat/custom-plugins-invoke

Conversation

@amiller
Copy link
Copy Markdown
Contributor

@amiller amiller commented Mar 3, 2026

Summary

  • Custom plugin type: owner writes arbitrary JS code as the capability endowment, with fetch, secrets, and store (persistent KV) as globals
  • POST /invoke/:permit_id: bearer-token-authenticated endpoint for calling custom capabilities directly — no JWT needed for callers
  • Browser approval UI: embedded HTML page served from the enclave at GET /approve/:id with secrets input, capability review, and bearer token display
  • CORS fix: requests carrying bearer tokens (or preflights requesting authorization) allow any origin — the token is the trust boundary, not the origin
  • DB changes: session expires_at + bearer_token columns, kv_store table for persistent custom capability state
  • JWT expiry fix: issueToken() was passing expiresIn=0, tokens expired instantly — now defaults to 24h

Test plan

  • Local test: custom capability claim + verify flow against GitHub API
  • CORS: verified preflight with Authorization in request headers gets Access-Control-Allow-Origin even when origin not in CORS_ORIGIN
  • Deploy to Phala CVM and test end-to-end with FC26 claim page
  • Verify rate limiting in custom capability store works across invocations

🤖 Generated with Claude Code

amiller and others added 6 commits March 3, 2026 12:00
- Custom plugin type: owner writes arbitrary JS code as the endowment
  with fetch, secrets, and persistent KV store globals
- POST /invoke/:permit_id — bearer-token-authenticated endpoint for
  calling custom capabilities directly (no JWT needed)
- Browser approval page (approve-html.ts) — embedded HTML UI served
  from the enclave for permit approval with secrets input
- CORS: bearer-token requests allow any origin (the token is the
  trust boundary, not the origin)
- Database: session expiry (expires_at), bearer_token column, kv_store
  table for persistent custom capability state
- JWT expiry fix: was passing expiresIn=0, now defaults to 24h
- Updated docker image digest in docker-compose.yml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Approval URLs now include &tee= so orchestrator HTML page knows which enclave to call
- Added amiller.github.io to staging CORS origins

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- browser/: Headless Playwright HTTP service (POST /browse) for
  cookie-authenticated YouTube/TikTok fetches from TEE
- openvpn-socks5/: OpenVPN→SOCKS5 container for local dev
- dstack/docker-compose.yml: Added socks5-relay (gost) + browser services
- Removed stale deploy/docker-compose.yml, docker-compose-sidecar.yaml
- Removed SQLite WAL files from tracking
- Auth fixes: owner JWT 24h→1yr, approve-html link fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes #4 — bearer tokens were generated on approval but never
returned in the sessions list, making web-approved permits unusable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Secrets were committed to this public repo in 591c430. All exposed
credentials have been rotated. This commit removes the file from
tracking and prevents future .env files from being committed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
amiller and others added 7 commits April 22, 2026 17:31
Case study of why one permit stayed live for weeks while 41 siblings
went stale. Covers the five decoupled ingredients (immutable capability
code, year-long bearer, out-of-band cookie refresh, static GitHub Pages
UI, untouched enclave), the DB evidence for the cookie-refresh
correlation, a clone-this-pattern recipe, and the sidecar SSH debug
checklist. Flags the unbuilt distribution path for the companion Chrome
extension as an open question.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Covers the dstack LUKS2 disk-encryption model, HKDF key derivation tied
to app_id + instance_id, what lives in each SQLite table, token
lifecycle, and Stage 0 limitations. README now points readers there and
corrects the env-template filename.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Exposes attestation/worker info from the CVM's dstack socket so clients
can verify what code is running. Proxies POST /prpc/Worker.Info on
/var/run/dstack.sock with a 5s timeout.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Custom capabilities now receive a refreshSecret(name, value) callback as
the 4th endowment argument. Primary use: cookies returned from a
TEE-internal browser fetch get written back as the secret so the next
invocation sees the rotated set. Browser service now returns cookies on
every /browse response to support this.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When /signup is called with an email, tenant_id is sha256(email) sliced
to 16 hex chars instead of random bytes. Same email → same tenant →
signup is idempotent. Anonymous signup (no email) keeps the random
tenant_N prefix.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds /push/vapid-key (public), /push/subscribe (owner) and /push/send
(owner) endpoints. VAPID keys are derived from the dstack KMS via
/var/run/tappd.sock so they're stable across restarts without being
stored anywhere. Subscriptions are owner-scoped secrets prefixed
PUSH_SUB_; /push/send fans out to all of them with a 10s per-tenant
cooldown, cleans up 410 Gone entries, and uses web-push for the actual
transport. docker-compose mounts tappd.sock and sets VAPID_SUBJECT.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
oauth3-proxy: sha256:2dfd4bb73c... (confirmed running on
app_23da7533b60fe6e5f5e30c97f30af5bd7ccdf4df via phala ps).
oauth3-browser: sha256:75c6c946f9...

This closes the last gap between what's committed and what's actually
running in the staging CVM.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant