{"id":51594386,"url":"https://github.com/drbaher/contract-ops-playground","last_synced_at":"2026-07-11T17:02:20.195Z","repository":{"id":359344266,"uuid":"1244829033","full_name":"DrBaher/contract-ops-playground","owner":"DrBaher","description":"Sandboxed in-browser playgrounds for the contract-ops CLI suite","archived":false,"fork":false,"pushed_at":"2026-05-21T12:20:25.000Z","size":74,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T20:54:56.506Z","etag":null,"topics":["agent-first","cli","contract-ops","demo","legal-tech","local-first","playground","sandbox"],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DrBaher.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-20T16:30:48.000Z","updated_at":"2026-05-21T12:20:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/DrBaher/contract-ops-playground","commit_stats":null,"previous_names":["drbaher/contract-ops-playground"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/DrBaher/contract-ops-playground","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcontract-ops-playground","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcontract-ops-playground/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcontract-ops-playground/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcontract-ops-playground/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DrBaher","download_url":"https://codeload.github.com/DrBaher/contract-ops-playground/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcontract-ops-playground/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35368768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-first","cli","contract-ops","demo","legal-tech","local-first","playground","sandbox"],"created_at":"2026-07-11T17:02:17.052Z","updated_at":"2026-07-11T17:02:20.180Z","avatar_url":"https://github.com/DrBaher.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# contract-ops-playground\n\nSandboxed, in-browser playgrounds for the [contract-ops CLI suite](https://cli.drbaher.com).\nEach playground takes **your** input, runs the real CLI on it in a hardened\nexecutor, and shows the result. Embeddable per tool page via `\u003ciframe\u003e`.\n\n\u003e ⚠️ **This service executes the suite CLIs on untrusted user input.** Read\n\u003e [Security](#security) before exposing it to the internet. Do **not** deploy it\n\u003e publicly without the controls below in place.\n\n## Status\n\n| Playground | Input | Status |\n|---|---|---|\n| **draft** | template + params JSON → filled doc | ✅ Phase 1 |\n| **compare** | two pasted versions → drift verdict + exit code | ✅ Phase 1 |\n| **docx2pdf** | `.docx` upload → downloadable PDF | ✅ Phase 2 (LibreOffice in image; **isolate per the warning below**) |\n| **template-vault** | seeded read-only vault explorer | ✅ Phase 3 |\n\n(nda-review and sign already have their own hosted demos.)\n\n## Run locally\n\n```bash\n# Point at local CLI clones (or omit to use the installed `draft` / `compare`):\nCOP_DRAFT_CMD=\"node /path/to/draft-cli/draft-cli.mjs\" \\\nCOP_COMPARE_CMD=\"node /path/to/compare-cli/compare-cli.mjs\" \\\n  npm start\n# → http://localhost:8080\nnpm test          # executor unit tests\n```\n\nEndpoints: `GET /` (UI), `GET /healthz`, `GET /api/meta`, `POST /api/run/\u003ccli\u003e`\n(JSON body of the playground's fields).\n\n## Security\n\nThe executor (`src/exec.mjs`) provides **process-level** defenses:\n\n- **No shell** — `execFile`, so user input is never interpreted as a command.\n- **Stripped env** — the child inherits *none* of the parent's secrets (LLM keys,\n  tokens). LLM tiers are also explicitly disabled (`draft --no-llm`). Demos are offline.\n- **Ephemeral cwd** — each run gets a fresh temp dir, deleted afterward. Input\n  files have fixed, server-chosen names (no path traversal).\n- **Timeout + output cap + input cap** — `COP_TIMEOUT_MS` (8s), `COP_MAX_OUTPUT`\n  (256 KB), `COP_MAX_INPUT` (64 KB/field), `COP_MAX_UPLOAD` (3 MB, docx2pdf).\n  Over-timeout runs are SIGKILLed; over-cap requests get a `413`.\n- **Per-IP rate limit** — `COP_RATE_MAX` runs/min (in-memory; single-instance).\n- **Strict CSP** on the UI; `x-content-type-options: nosniff`.\n\n**The deploy layer MUST add what a process can't self-enforce:**\n\n- **No outbound network egress** from the container (the CLIs need none here).\n- **Resource caps** — memory, pids, CPU (`docker run --memory --pids-limit --cpus`).\n- **Read-only rootfs** + a small `tmpfs` for `/tmp` (`--read-only --tmpfs /tmp`).\n- A WAF / Cloudflare Turnstile in front if abuse appears.\n- **Phase 2 (docx2pdf) raises the bar:** LibreOffice parsing untrusted `.docx`\n  is a real RCE/macro surface — run each conversion in a **disposable** locked\n  container (or gVisor/Firecracker), never in the long-lived server process, and\n  disable macros. Treat it as a separate hardening task.\n\n## Deploy (sketch — review first)\n\n```bash\ndocker build -t contract-ops-playground .\ndocker run -p 8080:8080 \\\n  --read-only --tmpfs /tmp --memory 512m --pids-limit 256 --cpus 1 \\\n  contract-ops-playground\n```\nThen host it (Railway/Fly/Render — same pattern as the nda-review/sign demos)\nand embed per tool page: `\u003ciframe src=\"https://…/?cli=draft\"\u003e`.\n\nPin the CLI versions in the Dockerfile to published releases before going live.\n\n## Embedding into the site (last-mile, needs a deploy URL)\n\nOnce deployed, wire it into the showcase site (`DrBaher/Drbaher-cli`) without\nbreaking the static build by gating on an env var:\n\n1. Add `PUBLIC_PLAYGROUND_URL=https://\u003cyour-playground-host\u003e` to the site's\n   Vercel env.\n2. On each tool page, render an iframe only when the var is set, e.g.:\n   ```astro\n   {import.meta.env.PUBLIC_PLAYGROUND_URL \u0026\u0026 (\n     \u003ciframe src={`${import.meta.env.PUBLIC_PLAYGROUND_URL}/?cli=draft`}\n             title=\"draft playground\" loading=\"lazy\"\n             sandbox=\"allow-scripts allow-forms allow-same-origin\"\n             class=\"w-full h-[520px] rounded-lg border\" /\u003e\n   )}\n   ```\n   Map `cli=` to each tool: `draft`, `compare`, `docx2pdf`, `template-vault`.\n3. Optionally add a combined `/play` page that tabs across all four.\n\nThe UI honors `?cli=\u003cid\u003e` and opens straight to that playground's tab, so the\nper-tool iframe snippet above works as-is. Embedding the bare URL defaults to\nthe draft tab.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrbaher%2Fcontract-ops-playground","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrbaher%2Fcontract-ops-playground","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrbaher%2Fcontract-ops-playground/lists"}