@mseep/open-computer-use 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (769) hide show
  1. package/.coderabbit.yaml +25 -0
  2. package/.dockerignore +95 -0
  3. package/.env.example +137 -0
  4. package/.githooks/pre-commit +68 -0
  5. package/.github/CODEOWNERS +125 -0
  6. package/.github/ISSUE_TEMPLATE/adr-proposal.md +41 -0
  7. package/.github/ISSUE_TEMPLATE/bug-report.md +49 -0
  8. package/.github/ISSUE_TEMPLATE/component-proposal.md +38 -0
  9. package/.github/ISSUE_TEMPLATE/config.yml +15 -0
  10. package/.github/ISSUE_TEMPLATE/dependency-proposal.md +59 -0
  11. package/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
  12. package/.github/ISSUE_TEMPLATE/nfr-proposal.md +44 -0
  13. package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  14. package/.github/codeql/codeql-config.yml +11 -0
  15. package/.github/codeql/extensions/security-models/python-sanitizers.model.yml +17 -0
  16. package/.github/codeql/extensions/security-models/qlpack.yml +7 -0
  17. package/.github/dependabot.yml +23 -0
  18. package/.github/security-exceptions.yml +23 -0
  19. package/.github/workflows/build.yml +420 -0
  20. package/.github/workflows/codeql.yml +33 -0
  21. package/.github/workflows/contracts-lint.yml +90 -0
  22. package/.github/workflows/docs-lint.yml +151 -0
  23. package/.github/workflows/helm.yml +131 -0
  24. package/.github/workflows/identity-lint.yml +30 -0
  25. package/.github/workflows/release-chart.yml +177 -0
  26. package/.github/workflows/release.yml +95 -0
  27. package/.github/workflows/security.yml +332 -0
  28. package/.github/workflows/stale.yml +31 -0
  29. package/.github/workflows/supply-chain.yml +242 -0
  30. package/.gitleaks.toml +53 -0
  31. package/.markdownlint.yaml +51 -0
  32. package/.semgrepignore +85 -0
  33. package/.vale/styles/Architecture/ap13-data-class-substrate.yml +12 -0
  34. package/.vale/styles/Architecture/banned-phrases.yml +23 -0
  35. package/.vale/styles/Architecture/banned-vocab.yml +23 -0
  36. package/.vale/styles/Architecture/marketing-tone.yml +19 -0
  37. package/.vale.ini +18 -0
  38. package/CHANGELOG.md +411 -0
  39. package/CLAUDE.md +218 -0
  40. package/CONTRIBUTING.md +82 -0
  41. package/Dockerfile +676 -0
  42. package/LICENSE +98 -0
  43. package/LICENSE-APACHE +202 -0
  44. package/LICENSE-MIT +21 -0
  45. package/NOTICE +36 -0
  46. package/README.md +516 -0
  47. package/SECURITY.md +45 -0
  48. package/THIRD-PARTY-LICENSES.md +14 -0
  49. package/apt-packages.txt +108 -0
  50. package/computer-use-server/.dockerignore +13 -0
  51. package/computer-use-server/Dockerfile +44 -0
  52. package/computer-use-server/README.md +84 -0
  53. package/computer-use-server/app.py +1544 -0
  54. package/computer-use-server/bin/list-subagent-models +449 -0
  55. package/computer-use-server/cli-defaults/README.md +31 -0
  56. package/computer-use-server/cli-defaults/codex.json +7 -0
  57. package/computer-use-server/cli-defaults/opencode.json +18 -0
  58. package/computer-use-server/cli_adapters/__init__.py +46 -0
  59. package/computer-use-server/cli_adapters/claude.py +163 -0
  60. package/computer-use-server/cli_adapters/codex.py +163 -0
  61. package/computer-use-server/cli_adapters/opencode.py +169 -0
  62. package/computer-use-server/cli_adapters/result.py +34 -0
  63. package/computer-use-server/cli_runtime.py +316 -0
  64. package/computer-use-server/context_vars.py +24 -0
  65. package/computer-use-server/docker_manager.py +1100 -0
  66. package/computer-use-server/docs_html.py +12 -0
  67. package/computer-use-server/mcp_resources.py +170 -0
  68. package/computer-use-server/mcp_tools.py +1430 -0
  69. package/computer-use-server/requirements.txt +17 -0
  70. package/computer-use-server/security.py +50 -0
  71. package/computer-use-server/skill_manager.py +664 -0
  72. package/computer-use-server/static/browser-viewer.js +445 -0
  73. package/computer-use-server/static/chart.umd.js +14 -0
  74. package/computer-use-server/static/docs.html +203 -0
  75. package/computer-use-server/static/github-dark.min.css +10 -0
  76. package/computer-use-server/static/github.min.css +10 -0
  77. package/computer-use-server/static/highlight.min.js +1213 -0
  78. package/computer-use-server/static/highlightjs-line-numbers.min.js +1 -0
  79. package/computer-use-server/static/icons.js +74 -0
  80. package/computer-use-server/static/jszip.min.js +13 -0
  81. package/computer-use-server/static/katex/auto-render.min.js +1 -0
  82. package/computer-use-server/static/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  83. package/computer-use-server/static/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  84. package/computer-use-server/static/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  85. package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  86. package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  87. package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  88. package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  89. package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  90. package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  91. package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  92. package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  93. package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  94. package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  95. package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  96. package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  97. package/computer-use-server/static/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  98. package/computer-use-server/static/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  99. package/computer-use-server/static/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  100. package/computer-use-server/static/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  101. package/computer-use-server/static/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  102. package/computer-use-server/static/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  103. package/computer-use-server/static/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  104. package/computer-use-server/static/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  105. package/computer-use-server/static/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  106. package/computer-use-server/static/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  107. package/computer-use-server/static/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  108. package/computer-use-server/static/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  109. package/computer-use-server/static/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  110. package/computer-use-server/static/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  111. package/computer-use-server/static/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  112. package/computer-use-server/static/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  113. package/computer-use-server/static/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  114. package/computer-use-server/static/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  115. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  116. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  117. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  118. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  119. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  120. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  121. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  122. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  123. package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  124. package/computer-use-server/static/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  125. package/computer-use-server/static/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  126. package/computer-use-server/static/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  127. package/computer-use-server/static/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  128. package/computer-use-server/static/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  129. package/computer-use-server/static/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  130. package/computer-use-server/static/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  131. package/computer-use-server/static/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  132. package/computer-use-server/static/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  133. package/computer-use-server/static/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  134. package/computer-use-server/static/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  135. package/computer-use-server/static/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  136. package/computer-use-server/static/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  137. package/computer-use-server/static/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  138. package/computer-use-server/static/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  139. package/computer-use-server/static/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  140. package/computer-use-server/static/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  141. package/computer-use-server/static/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  142. package/computer-use-server/static/katex/katex.min.css +1 -0
  143. package/computer-use-server/static/katex/katex.min.js +1 -0
  144. package/computer-use-server/static/locale.js +242 -0
  145. package/computer-use-server/static/mammoth.browser.min.js +21 -0
  146. package/computer-use-server/static/marked.min.js +6 -0
  147. package/computer-use-server/static/mermaid.min.js +2811 -0
  148. package/computer-use-server/static/pdf.min.js +22 -0
  149. package/computer-use-server/static/pdf.worker.min.js +22 -0
  150. package/computer-use-server/static/pptxviewjs.min.js +1 -0
  151. package/computer-use-server/static/preact-htm.min.js +1 -0
  152. package/computer-use-server/static/preview.css +1030 -0
  153. package/computer-use-server/static/preview.js +1522 -0
  154. package/computer-use-server/static/xlsx.full.min.js +22 -0
  155. package/computer-use-server/static/xterm-addon-fit.min.js +2 -0
  156. package/computer-use-server/static/xterm-addon-web-links.min.js +2 -0
  157. package/computer-use-server/static/xterm.css +218 -0
  158. package/computer-use-server/static/xterm.min.js +2 -0
  159. package/computer-use-server/system_prompt.py +761 -0
  160. package/computer-use-server/uploads.py +82 -0
  161. package/contracts/README.md +53 -0
  162. package/contracts/audit/audit-fanin.asyncapi.yaml +407 -0
  163. package/contracts/exec/exec-channel.schema.json +240 -0
  164. package/contracts/mcp/2025-06-18/ocu-constraints.schema.json +178 -0
  165. package/contracts/storage/file-artifact-api.schema.json +390 -0
  166. package/contracts/storage/file-ops.schema.json +217 -0
  167. package/contracts/storage/mount-config.schema.json +197 -0
  168. package/cron/Dockerfile +15 -0
  169. package/cron/cleanup-quick.sh +21 -0
  170. package/cron/cleanup.sh +127 -0
  171. package/data/outputs/.gitkeep +0 -0
  172. package/data/uploads/.gitkeep +0 -0
  173. package/docker-compose.test.yml +54 -0
  174. package/docker-compose.webui.yml +77 -0
  175. package/docker-compose.yml +96 -0
  176. package/docs/CLOUD.md +29 -0
  177. package/docs/COMPARISON.md +128 -0
  178. package/docs/DOCKER.md +469 -0
  179. package/docs/DYNAMIC-SKILLS.md +77 -0
  180. package/docs/FEATURES.md +100 -0
  181. package/docs/INSTALL.md +111 -0
  182. package/docs/KNOWN-BUGS.md +86 -0
  183. package/docs/MCP.md +320 -0
  184. package/docs/SCREENSHOTS.md +39 -0
  185. package/docs/SKILLS-USER-GUIDE.md +86 -0
  186. package/docs/SKILLS.md +483 -0
  187. package/docs/TERMINAL-TAB.md +56 -0
  188. package/docs/architecture/02-trust-boundaries.md +224 -0
  189. package/docs/architecture/03-c4-context.md +61 -0
  190. package/docs/architecture/04-bounded-contexts.md +119 -0
  191. package/docs/architecture/05-c4-container.md +88 -0
  192. package/docs/architecture/06-threat-model.md +172 -0
  193. package/docs/architecture/08-contracts.md +105 -0
  194. package/docs/architecture/MANIFESTO.md +38 -0
  195. package/docs/architecture/PROCESS.md +64 -0
  196. package/docs/architecture/README.md +37 -0
  197. package/docs/architecture/adr/0000-template.md +65 -0
  198. package/docs/architecture/adr/0001-layer-0-gate-legacy-exclusion.md +75 -0
  199. package/docs/architecture/adr/0002-session-view-descriptor.md +57 -0
  200. package/docs/architecture/adr/0003-sandbox-runtime-tier-ladder.md +63 -0
  201. package/docs/architecture/adr/0004-operator-authentication-substrate.md +63 -0
  202. package/docs/architecture/adr/0005-egress-credential-delivery-envoy-sds.md +62 -0
  203. package/docs/architecture/adr/0006-egress-forward-proxy-substrate.md +65 -0
  204. package/docs/architecture/adr/0007-egress-auth-mechanism.md +72 -0
  205. package/docs/architecture/adr/0008-session-egress-attribution.md +59 -0
  206. package/docs/architecture/adr/0009-audit-pipeline-pluggable-by-contract.md +76 -0
  207. package/docs/architecture/adr/0010-storage-backend-pluggable-adapter.md +60 -0
  208. package/docs/architecture/adr/0011-storage-egress-lane.md +67 -0
  209. package/docs/architecture/adr/0012-implementation-language.md +67 -0
  210. package/docs/architecture/adr/0020-sandbox-image-provisioning.md +82 -0
  211. package/docs/architecture/adr/README.md +53 -0
  212. package/docs/architecture/compliance/.gitkeep +0 -0
  213. package/docs/architecture/components/00-overview.md +42 -0
  214. package/docs/architecture/components/0000-template.md +50 -0
  215. package/docs/architecture/components/01-mcp-gateway.md +80 -0
  216. package/docs/architecture/components/02-control-operator-api.md +80 -0
  217. package/docs/architecture/components/04-storage-broker.md +104 -0
  218. package/docs/architecture/components/05-session-sandbox.md +93 -0
  219. package/docs/architecture/components/06-egress-trust-edge.md +95 -0
  220. package/docs/architecture/components/07-audit-pipeline.md +110 -0
  221. package/docs/architecture/diagrams/.gitkeep +0 -0
  222. package/docs/architecture/diagrams/02-trust-boundaries.mmd +111 -0
  223. package/docs/architecture/diagrams/06-threat-model.mmd +41 -0
  224. package/docs/architecture/diagrams/08-contracts.mmd +47 -0
  225. package/docs/architecture/diagrams/c4-container.mmd +59 -0
  226. package/docs/architecture/diagrams/c4-context.mmd +46 -0
  227. package/docs/architecture/glossary.md +172 -0
  228. package/docs/architecture/manifesto/.gitkeep +0 -0
  229. package/docs/architecture/manifesto/01-audience-and-buyer.md +57 -0
  230. package/docs/architecture/manifesto/02-nfrs.md +325 -0
  231. package/docs/architecture/manifesto/03-non-negotiables.md +35 -0
  232. package/docs/architecture/manifesto/04-non-goals.md +23 -0
  233. package/docs/architecture/manifesto/05-licensing-posture.md +61 -0
  234. package/docs/architecture/manifesto/06-starter-mode-policy.md +49 -0
  235. package/docs/architecture/manifesto/07-governance.md +60 -0
  236. package/docs/architecture/primitives-backlog.md +51 -0
  237. package/docs/architecture.svg +117 -0
  238. package/docs/claude-code-gateway.md +173 -0
  239. package/docs/cli-config-templates.md +240 -0
  240. package/docs/data-flow.svg +72 -0
  241. package/docs/demo-landing-page.gif +0 -0
  242. package/docs/demo-qwen-trending.gif +0 -0
  243. package/docs/dynamic-skills.svg +77 -0
  244. package/docs/file-flow.svg +126 -0
  245. package/docs/future-architecture/README.md +152 -0
  246. package/docs/future-architecture/adr/0001-control-plane-language-go.md +80 -0
  247. package/docs/future-architecture/adr/0002-guest-agent-language-go.md +84 -0
  248. package/docs/future-architecture/adr/0003-docker-poc-first-then-k8s.md +37 -0
  249. package/docs/future-architecture/adr/0004-pluggable-runtime-via-runtimeclass.md +34 -0
  250. package/docs/future-architecture/adr/0005-mcp-as-control-plane-gateway.md +34 -0
  251. package/docs/future-architecture/adr/0006-no-agpl-no-bsl-dependencies.md +41 -0
  252. package/docs/future-architecture/adr/0007-superseded-by-future-architecture.md +37 -0
  253. package/docs/future-architecture/adr/0008-internal-grpc-external-rest-mcp.md +106 -0
  254. package/docs/future-architecture/adr/0009-external-protocol-dialects.md +94 -0
  255. package/docs/future-architecture/adr/0010-lambda-as-inspiration-not-runtime.md +86 -0
  256. package/docs/future-architecture/adr/0011-kata-as-first-class-dind-runtime.md +84 -0
  257. package/docs/future-architecture/antipatterns.md +552 -0
  258. package/docs/future-architecture/architecture/01-layers.md +109 -0
  259. package/docs/future-architecture/architecture/02-layer4-control-plane.md +122 -0
  260. package/docs/future-architecture/architecture/03-layer3-providers.md +174 -0
  261. package/docs/future-architecture/architecture/04-layer2-runtimes.md +114 -0
  262. package/docs/future-architecture/architecture/04b-credential-broker.md +153 -0
  263. package/docs/future-architecture/architecture/05-layer1-guest-agent.md +138 -0
  264. package/docs/future-architecture/architecture/06-storage.md +134 -0
  265. package/docs/future-architecture/architecture/07-security.md +194 -0
  266. package/docs/future-architecture/architecture/08-networking.md +149 -0
  267. package/docs/future-architecture/architecture/09-templates.md +122 -0
  268. package/docs/future-architecture/architecture/10-observability.md +121 -0
  269. package/docs/future-architecture/design-notes.md +72 -0
  270. package/docs/future-architecture/gaps.md +281 -0
  271. package/docs/future-architecture/phase-template.md +123 -0
  272. package/docs/future-architecture/references.md +225 -0
  273. package/docs/future-architecture/research/01-kata-containers.md +100 -0
  274. package/docs/future-architecture/research/02-e2b-infra.md +133 -0
  275. package/docs/future-architecture/research/03-coder.md +115 -0
  276. package/docs/future-architecture/research/04-cloud-hypervisor.md +99 -0
  277. package/docs/future-architecture/research/05-firecracker.md +114 -0
  278. package/docs/future-architecture/research/06-agent-sandbox.md +142 -0
  279. package/docs/future-architecture/research/07-chromedp.md +78 -0
  280. package/docs/future-architecture/research/08-microsandbox.md +78 -0
  281. package/docs/future-architecture/research/09-agentbox.md +135 -0
  282. package/docs/future-architecture/research/10-sysbox.md +100 -0
  283. package/docs/future-architecture/research/11-firecracker-containerd.md +93 -0
  284. package/docs/future-architecture/research/12-docker-socket-proxy.md +59 -0
  285. package/docs/future-architecture/research/14-e2b-desktop-and-surf.md +107 -0
  286. package/docs/future-architecture/research/18-open-webui-terminals-observed.md +135 -0
  287. package/docs/future-architecture/research/bank-buyer.md +96 -0
  288. package/docs/future-architecture/research/enthusiast-audience.md +106 -0
  289. package/docs/future-architecture/research/proof-uipath-anthropic-2026-05.md +76 -0
  290. package/docs/future-architecture/research/widemoat-thesis-advisor.md +124 -0
  291. package/docs/future-architecture/roadmap.md +438 -0
  292. package/docs/kata-runtime.md +267 -0
  293. package/docs/kubernetes.md +86 -0
  294. package/docs/logo.png +0 -0
  295. package/docs/multi-cli.md +161 -0
  296. package/docs/openwebui-filter.md +134 -0
  297. package/docs/roadmap/implementation-roadmap.md +104 -0
  298. package/docs/sandbox-contents.svg +229 -0
  299. package/docs/screenshots/01-create-document.png +0 -0
  300. package/docs/screenshots/02-file-preview.png +0 -0
  301. package/docs/screenshots/03-browser-viewer.png +0 -0
  302. package/docs/screenshots/04-sub-agent-terminal.png +0 -0
  303. package/docs/screenshots/05-chat-overview.png +0 -0
  304. package/docs/screenshots/06-sub-agent-dashboard.png +0 -0
  305. package/docs/screenshots/07-frontend-design-skill.png +0 -0
  306. package/docs/screenshots/08-pptx-skill.png +0 -0
  307. package/docs/screenshots/09-skill-creator.png +0 -0
  308. package/docs/screenshots/10-data-chart.png +0 -0
  309. package/docs/shared-browser.svg +102 -0
  310. package/docs/system-prompt.md +113 -0
  311. package/docs/terminal-flow.svg +69 -0
  312. package/examples/helm/README.md +20 -0
  313. package/examples/helm/standalone/values.yaml +49 -0
  314. package/examples/helm/with-open-webui/README.md +99 -0
  315. package/examples/helm/with-open-webui/values-computer-use.yaml +32 -0
  316. package/examples/helm/with-open-webui/values-open-webui.yaml +67 -0
  317. package/fonts/NotoEmoji-Regular.ttf +0 -0
  318. package/helm/computer-use-server/.helmignore +17 -0
  319. package/helm/computer-use-server/Chart.yaml +32 -0
  320. package/helm/computer-use-server/README.md +211 -0
  321. package/helm/computer-use-server/templates/NOTES.txt +66 -0
  322. package/helm/computer-use-server/templates/_helpers.tpl +115 -0
  323. package/helm/computer-use-server/templates/configmap-dind-init.yaml +82 -0
  324. package/helm/computer-use-server/templates/configmap.yaml +18 -0
  325. package/helm/computer-use-server/templates/deployment.yaml +248 -0
  326. package/helm/computer-use-server/templates/ingress.yaml +38 -0
  327. package/helm/computer-use-server/templates/networkpolicy.yaml +50 -0
  328. package/helm/computer-use-server/templates/pdb.yaml +16 -0
  329. package/helm/computer-use-server/templates/pvc-data.yaml +20 -0
  330. package/helm/computer-use-server/templates/pvc-skills-cache.yaml +20 -0
  331. package/helm/computer-use-server/templates/pvc-user-data.yaml +20 -0
  332. package/helm/computer-use-server/templates/pvc-var-lib-docker.yaml +27 -0
  333. package/helm/computer-use-server/templates/secret.yaml +23 -0
  334. package/helm/computer-use-server/templates/service.yaml +22 -0
  335. package/helm/computer-use-server/templates/serviceaccount.yaml +15 -0
  336. package/helm/computer-use-server/templates/tests/test-health.yaml +23 -0
  337. package/helm/computer-use-server/values.schema.json +183 -0
  338. package/helm/computer-use-server/values.yaml +297 -0
  339. package/lychee.toml +36 -0
  340. package/openwebui/Dockerfile +52 -0
  341. package/openwebui/README.md +38 -0
  342. package/openwebui/functions/README.md +48 -0
  343. package/openwebui/functions/computer_link_filter.py +487 -0
  344. package/openwebui/init.sh +305 -0
  345. package/openwebui/patches/README.md +44 -0
  346. package/openwebui/patches/fix_artifacts_auto_show.py +441 -0
  347. package/openwebui/patches/fix_attached_files_position.py +87 -0
  348. package/openwebui/patches/fix_large_tool_args.py +156 -0
  349. package/openwebui/patches/fix_large_tool_results.py +289 -0
  350. package/openwebui/patches/fix_preview_url_detection.py +230 -0
  351. package/openwebui/patches/fix_skip_embedding_chat_files.py +229 -0
  352. package/openwebui/patches/fix_skip_rag_files_native_fc.py +100 -0
  353. package/openwebui/patches/fix_tool_loop_errors.py +510 -0
  354. package/package.json +39 -0
  355. package/requirements.txt +112 -0
  356. package/scripts/check-config.sh +141 -0
  357. package/scripts/docs-lint/ai-slop-detector.sh +202 -0
  358. package/scripts/docs-lint/architecture-tree-whitelist.sh +131 -0
  359. package/scripts/docs-lint/ascii-diagram-detector.sh +58 -0
  360. package/scripts/docs-lint/front-matter-validator.sh +97 -0
  361. package/scripts/docs-lint/gitignored-ref-detector.sh +122 -0
  362. package/scripts/docs-lint/identity-email-detector.sh +48 -0
  363. package/scripts/docs-lint/test-linters.sh +354 -0
  364. package/scripts/docs-lint/wc-budget.sh +61 -0
  365. package/scripts/githooks/pre-push +75 -0
  366. package/server.json +13 -0
  367. package/settings-wrapper/Dockerfile +9 -0
  368. package/settings-wrapper/README.md +119 -0
  369. package/settings-wrapper/app.py +113 -0
  370. package/settings-wrapper/requirements.txt +2 -0
  371. package/settings-wrapper/skills.json +25 -0
  372. package/skills/README.md +46 -0
  373. package/skills/examples/algorithmic-art/SKILL.md +405 -0
  374. package/skills/examples/algorithmic-art/templates/generator_template.js +223 -0
  375. package/skills/examples/algorithmic-art/templates/viewer.html +601 -0
  376. package/skills/examples/artifacts-builder/SKILL.md +74 -0
  377. package/skills/examples/artifacts-builder/scripts/bundle-artifact.sh +54 -0
  378. package/skills/examples/artifacts-builder/scripts/init-artifact.sh +322 -0
  379. package/skills/examples/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  380. package/skills/examples/canvas-design/LICENSE.txt +202 -0
  381. package/skills/examples/canvas-design/SKILL.md +130 -0
  382. package/skills/examples/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  383. package/skills/examples/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  384. package/skills/examples/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  385. package/skills/examples/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
  386. package/skills/examples/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  387. package/skills/examples/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
  388. package/skills/examples/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  389. package/skills/examples/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  390. package/skills/examples/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  391. package/skills/examples/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  392. package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  393. package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  394. package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  395. package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  396. package/skills/examples/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
  397. package/skills/examples/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  398. package/skills/examples/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
  399. package/skills/examples/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  400. package/skills/examples/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  401. package/skills/examples/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
  402. package/skills/examples/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  403. package/skills/examples/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
  404. package/skills/examples/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  405. package/skills/examples/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  406. package/skills/examples/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  407. package/skills/examples/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  408. package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  409. package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  410. package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  411. package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  412. package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  413. package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  414. package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  415. package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  416. package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  417. package/skills/examples/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  418. package/skills/examples/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  419. package/skills/examples/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
  420. package/skills/examples/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  421. package/skills/examples/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  422. package/skills/examples/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  423. package/skills/examples/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  424. package/skills/examples/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  425. package/skills/examples/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  426. package/skills/examples/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
  427. package/skills/examples/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  428. package/skills/examples/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  429. package/skills/examples/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  430. package/skills/examples/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  431. package/skills/examples/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  432. package/skills/examples/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  433. package/skills/examples/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  434. package/skills/examples/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  435. package/skills/examples/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
  436. package/skills/examples/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  437. package/skills/examples/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  438. package/skills/examples/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  439. package/skills/examples/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  440. package/skills/examples/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  441. package/skills/examples/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  442. package/skills/examples/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  443. package/skills/examples/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
  444. package/skills/examples/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
  445. package/skills/examples/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  446. package/skills/examples/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  447. package/skills/examples/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
  448. package/skills/examples/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  449. package/skills/examples/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
  450. package/skills/examples/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  451. package/skills/examples/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  452. package/skills/examples/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
  453. package/skills/examples/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  454. package/skills/examples/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  455. package/skills/examples/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  456. package/skills/examples/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  457. package/skills/examples/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  458. package/skills/examples/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  459. package/skills/examples/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
  460. package/skills/examples/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  461. package/skills/examples/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  462. package/skills/examples/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  463. package/skills/examples/copy-editing/SKILL.md +447 -0
  464. package/skills/examples/copy-editing/evals/evals.json +89 -0
  465. package/skills/examples/copy-editing/references/plain-english-alternatives.md +394 -0
  466. package/skills/examples/internal-comms/LICENSE.txt +202 -0
  467. package/skills/examples/internal-comms/SKILL.md +32 -0
  468. package/skills/examples/internal-comms/examples/3p-updates.md +47 -0
  469. package/skills/examples/internal-comms/examples/company-newsletter.md +65 -0
  470. package/skills/examples/internal-comms/examples/faq-answers.md +30 -0
  471. package/skills/examples/internal-comms/examples/general-comms.md +16 -0
  472. package/skills/examples/mcp-builder/SKILL.md +328 -0
  473. package/skills/examples/mcp-builder/reference/evaluation.md +602 -0
  474. package/skills/examples/mcp-builder/reference/mcp_best_practices.md +915 -0
  475. package/skills/examples/mcp-builder/reference/node_mcp_server.md +916 -0
  476. package/skills/examples/mcp-builder/reference/python_mcp_server.md +752 -0
  477. package/skills/examples/mcp-builder/scripts/connections.py +151 -0
  478. package/skills/examples/mcp-builder/scripts/evaluation.py +373 -0
  479. package/skills/examples/mcp-builder/scripts/example_evaluation.xml +22 -0
  480. package/skills/examples/mcp-builder/scripts/requirements.txt +2 -0
  481. package/skills/examples/product-marketing-context/SKILL.md +241 -0
  482. package/skills/examples/product-marketing-context/evals/evals.json +85 -0
  483. package/skills/examples/single-cell-rna-qc/SKILL.md +175 -0
  484. package/skills/examples/single-cell-rna-qc/references/scverse_qc_guidelines.md +186 -0
  485. package/skills/examples/single-cell-rna-qc/scripts/qc_analysis.py +232 -0
  486. package/skills/examples/single-cell-rna-qc/scripts/qc_core.py +233 -0
  487. package/skills/examples/single-cell-rna-qc/scripts/qc_plotting.py +235 -0
  488. package/skills/examples/skill-creator/SKILL.md +355 -0
  489. package/skills/examples/skill-creator/references/output-patterns.md +82 -0
  490. package/skills/examples/skill-creator/references/workflows.md +28 -0
  491. package/skills/examples/skill-creator/scripts/init_skill.py +303 -0
  492. package/skills/examples/skill-creator/scripts/package_skill.py +110 -0
  493. package/skills/examples/skill-creator/scripts/quick_validate.py +95 -0
  494. package/skills/examples/slack-gif-creator/SKILL.md +254 -0
  495. package/skills/examples/slack-gif-creator/core/easing.py +234 -0
  496. package/skills/examples/slack-gif-creator/core/frame_composer.py +176 -0
  497. package/skills/examples/slack-gif-creator/core/gif_builder.py +269 -0
  498. package/skills/examples/slack-gif-creator/core/validators.py +136 -0
  499. package/skills/examples/slack-gif-creator/requirements.txt +4 -0
  500. package/skills/examples/social-content/SKILL.md +278 -0
  501. package/skills/examples/social-content/evals/evals.json +92 -0
  502. package/skills/examples/social-content/references/platforms.md +170 -0
  503. package/skills/examples/social-content/references/post-templates.md +177 -0
  504. package/skills/examples/social-content/references/reverse-engineering.md +195 -0
  505. package/skills/examples/theme-factory/SKILL.md +59 -0
  506. package/skills/examples/theme-factory/theme-showcase.pdf +0 -0
  507. package/skills/examples/theme-factory/themes/arctic-frost.md +19 -0
  508. package/skills/examples/theme-factory/themes/botanical-garden.md +19 -0
  509. package/skills/examples/theme-factory/themes/desert-rose.md +19 -0
  510. package/skills/examples/theme-factory/themes/forest-canopy.md +19 -0
  511. package/skills/examples/theme-factory/themes/golden-hour.md +19 -0
  512. package/skills/examples/theme-factory/themes/midnight-galaxy.md +19 -0
  513. package/skills/examples/theme-factory/themes/modern-minimalist.md +19 -0
  514. package/skills/examples/theme-factory/themes/ocean-depths.md +19 -0
  515. package/skills/examples/theme-factory/themes/sunset-boulevard.md +19 -0
  516. package/skills/examples/theme-factory/themes/tech-innovation.md +19 -0
  517. package/skills/examples/web-artifacts-builder/LICENSE.txt +202 -0
  518. package/skills/examples/web-artifacts-builder/SKILL.md +74 -0
  519. package/skills/examples/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  520. package/skills/examples/web-artifacts-builder/scripts/init-artifact.sh +322 -0
  521. package/skills/examples/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  522. package/skills/examples/writing-skills/SKILL.md +655 -0
  523. package/skills/examples/writing-skills/anthropic-best-practices.md +1150 -0
  524. package/skills/examples/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  525. package/skills/examples/writing-skills/graphviz-conventions.dot +172 -0
  526. package/skills/examples/writing-skills/persuasion-principles.md +187 -0
  527. package/skills/examples/writing-skills/render-graphs.js +168 -0
  528. package/skills/examples/writing-skills/testing-skills-with-subagents.md +384 -0
  529. package/skills/public/describe-image/SKILL.md +105 -0
  530. package/skills/public/describe-image/scripts/describe.py +389 -0
  531. package/skills/public/doc-coauthoring/SKILL.md +375 -0
  532. package/skills/public/docx/LICENSE.txt +30 -0
  533. package/skills/public/docx/SKILL.md +199 -0
  534. package/skills/public/docx/docx-js.md +350 -0
  535. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  536. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  537. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  538. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  539. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  540. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  541. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  542. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  543. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  544. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  545. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  546. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  547. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  548. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  549. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  550. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  551. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  552. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  553. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  554. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  555. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  556. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  557. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  558. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  559. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  560. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  561. package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  562. package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  563. package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  564. package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  565. package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  566. package/skills/public/docx/ooxml/schemas/mce/mc.xsd +75 -0
  567. package/skills/public/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  568. package/skills/public/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  569. package/skills/public/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  570. package/skills/public/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  571. package/skills/public/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  572. package/skills/public/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  573. package/skills/public/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  574. package/skills/public/docx/ooxml/scripts/pack.py +159 -0
  575. package/skills/public/docx/ooxml/scripts/unpack.py +29 -0
  576. package/skills/public/docx/ooxml/scripts/validate.py +69 -0
  577. package/skills/public/docx/ooxml/scripts/validation/__init__.py +15 -0
  578. package/skills/public/docx/ooxml/scripts/validation/base.py +951 -0
  579. package/skills/public/docx/ooxml/scripts/validation/docx.py +274 -0
  580. package/skills/public/docx/ooxml/scripts/validation/pptx.py +315 -0
  581. package/skills/public/docx/ooxml/scripts/validation/redlining.py +279 -0
  582. package/skills/public/docx/ooxml.md +632 -0
  583. package/skills/public/docx/scripts/__init__.py +1 -0
  584. package/skills/public/docx/scripts/document.py +1292 -0
  585. package/skills/public/docx/scripts/templates/comments.xml +3 -0
  586. package/skills/public/docx/scripts/templates/commentsExtended.xml +3 -0
  587. package/skills/public/docx/scripts/templates/commentsExtensible.xml +3 -0
  588. package/skills/public/docx/scripts/templates/commentsIds.xml +3 -0
  589. package/skills/public/docx/scripts/templates/people.xml +3 -0
  590. package/skills/public/docx/scripts/utilities.py +374 -0
  591. package/skills/public/file-reading/LICENSE.txt +30 -0
  592. package/skills/public/file-reading/SKILL.md +350 -0
  593. package/skills/public/frontend-design/LICENSE.txt +177 -0
  594. package/skills/public/frontend-design/SKILL.md +42 -0
  595. package/skills/public/gitlab-explorer/SKILL.md +174 -0
  596. package/skills/public/gitlab-explorer/references/git-commands.md +323 -0
  597. package/skills/public/gitlab-explorer/references/glab-commands.md +282 -0
  598. package/skills/public/gitlab-explorer/scripts/check_gitlab_auth.sh +109 -0
  599. package/skills/public/pdf/FORMS.md +205 -0
  600. package/skills/public/pdf/REFERENCE.md +612 -0
  601. package/skills/public/pdf/SKILL.md +364 -0
  602. package/skills/public/pdf/scripts/check_bounding_boxes.py +70 -0
  603. package/skills/public/pdf/scripts/check_bounding_boxes_test.py +226 -0
  604. package/skills/public/pdf/scripts/check_fillable_fields.py +12 -0
  605. package/skills/public/pdf/scripts/convert_pdf_to_images.py +35 -0
  606. package/skills/public/pdf/scripts/create_validation_image.py +41 -0
  607. package/skills/public/pdf/scripts/extract_form_field_info.py +152 -0
  608. package/skills/public/pdf/scripts/fill_fillable_fields.py +114 -0
  609. package/skills/public/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  610. package/skills/public/pdf-reading/LICENSE.txt +30 -0
  611. package/skills/public/pdf-reading/REFERENCE.md +196 -0
  612. package/skills/public/pdf-reading/SKILL.md +305 -0
  613. package/skills/public/playwright-cli/SKILL.md +278 -0
  614. package/skills/public/playwright-cli/references/request-mocking.md +87 -0
  615. package/skills/public/playwright-cli/references/running-code.md +232 -0
  616. package/skills/public/playwright-cli/references/session-management.md +169 -0
  617. package/skills/public/playwright-cli/references/storage-state.md +275 -0
  618. package/skills/public/playwright-cli/references/test-generation.md +88 -0
  619. package/skills/public/playwright-cli/references/tracing.md +139 -0
  620. package/skills/public/playwright-cli/references/video-recording.md +43 -0
  621. package/skills/public/pptx/LICENSE.txt +30 -0
  622. package/skills/public/pptx/SKILL.md +484 -0
  623. package/skills/public/pptx/css.md +335 -0
  624. package/skills/public/pptx/html2pptx.md +893 -0
  625. package/skills/public/pptx/html2pptx.tgz +0 -0
  626. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  627. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  628. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  629. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  630. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  631. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  632. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  633. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  634. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  635. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  636. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  637. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  638. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  639. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  640. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  641. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  642. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  643. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  644. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  645. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  646. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  647. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  648. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  649. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  650. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  651. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  652. package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  653. package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  654. package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  655. package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  656. package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  657. package/skills/public/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  658. package/skills/public/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  659. package/skills/public/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  660. package/skills/public/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  661. package/skills/public/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  662. package/skills/public/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  663. package/skills/public/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  664. package/skills/public/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  665. package/skills/public/pptx/ooxml/scripts/pack.py +159 -0
  666. package/skills/public/pptx/ooxml/scripts/unpack.py +29 -0
  667. package/skills/public/pptx/ooxml/scripts/validate.py +69 -0
  668. package/skills/public/pptx/ooxml/scripts/validation/__init__.py +15 -0
  669. package/skills/public/pptx/ooxml/scripts/validation/base.py +951 -0
  670. package/skills/public/pptx/ooxml/scripts/validation/docx.py +274 -0
  671. package/skills/public/pptx/ooxml/scripts/validation/pptx.py +315 -0
  672. package/skills/public/pptx/ooxml/scripts/validation/redlining.py +279 -0
  673. package/skills/public/pptx/ooxml.md +427 -0
  674. package/skills/public/pptx/scripts/inventory.py +1020 -0
  675. package/skills/public/pptx/scripts/rearrange.py +231 -0
  676. package/skills/public/pptx/scripts/replace.py +385 -0
  677. package/skills/public/pptx/scripts/thumbnail.py +450 -0
  678. package/skills/public/skill-creator/SKILL.md +356 -0
  679. package/skills/public/skill-creator/references/output-patterns.md +82 -0
  680. package/skills/public/skill-creator/references/workflows.md +28 -0
  681. package/skills/public/skill-creator/scripts/init_skill.py +303 -0
  682. package/skills/public/skill-creator/scripts/package_skill.py +110 -0
  683. package/skills/public/skill-creator/scripts/quick_validate.py +95 -0
  684. package/skills/public/sub-agent/SKILL.md +186 -0
  685. package/skills/public/sub-agent/references/security-review.md +153 -0
  686. package/skills/public/sub-agent/references/usage.md +207 -0
  687. package/skills/public/sub-agent/scripts/list_subagent_models.sh +22 -0
  688. package/skills/public/test-driven-development/SKILL.md +371 -0
  689. package/skills/public/test-driven-development/testing-anti-patterns.md +299 -0
  690. package/skills/public/webapp-testing/LICENSE.txt +202 -0
  691. package/skills/public/webapp-testing/SKILL.md +96 -0
  692. package/skills/public/webapp-testing/examples/console_logging.py +35 -0
  693. package/skills/public/webapp-testing/examples/element_discovery.py +40 -0
  694. package/skills/public/webapp-testing/examples/static_html_automation.py +33 -0
  695. package/skills/public/webapp-testing/scripts/with_server.py +106 -0
  696. package/skills/public/xlsx/LICENSE.txt +30 -0
  697. package/skills/public/xlsx/SKILL.md +316 -0
  698. package/skills/public/xlsx/preview_data.py +93 -0
  699. package/skills/public/xlsx/recalc.py +178 -0
  700. package/tests/README.md +42 -0
  701. package/tests/fixtures/cli/claude_v0.9.2.0_argv.json +46 -0
  702. package/tests/fixtures/cli/claude_v0.9.2.0_stdout.json +32 -0
  703. package/tests/fixtures/cli/codex_run.jsonl +4 -0
  704. package/tests/fixtures/cli/opencode_run.jsonl +6 -0
  705. package/tests/integration/README.md +56 -0
  706. package/tests/integration/conftest.py +280 -0
  707. package/tests/integration/pytest.ini +13 -0
  708. package/tests/integration/test_mcp_auth.py +85 -0
  709. package/tests/integration/test_mcp_tools.py +101 -0
  710. package/tests/integration/test_workspace_lifecycle.py +125 -0
  711. package/tests/orchestrator/mock_llm_server.py +343 -0
  712. package/tests/orchestrator/test_cli_adapters.py +566 -0
  713. package/tests/orchestrator/test_cli_adapters_live.py +527 -0
  714. package/tests/orchestrator/test_cli_runtime.py +451 -0
  715. package/tests/orchestrator/test_docker_manager.py +302 -0
  716. package/tests/orchestrator/test_dynamic_instructions.py +69 -0
  717. package/tests/orchestrator/test_mcp_resources.py +140 -0
  718. package/tests/orchestrator/test_mcp_tools.py +224 -0
  719. package/tests/orchestrator/test_passthrough_isolation.py +201 -0
  720. package/tests/orchestrator/test_readme_in_container.py +76 -0
  721. package/tests/orchestrator/test_render_cache.py +84 -0
  722. package/tests/orchestrator/test_runtime_cli_endpoint.py +108 -0
  723. package/tests/orchestrator/test_single_user_mode.py +212 -0
  724. package/tests/orchestrator/test_startup_warnings.py +123 -0
  725. package/tests/orchestrator/test_sub_agent_dispatch.py +327 -0
  726. package/tests/orchestrator/test_subagent_claude_compat.py +367 -0
  727. package/tests/orchestrator/test_system_prompt_endpoint.py +191 -0
  728. package/tests/orchestrator/test_tool_descriptions.py +52 -0
  729. package/tests/orchestrator/test_view_image.py +201 -0
  730. package/tests/patches/conftest.py +30 -0
  731. package/tests/patches/fixtures/__init__.py +10 -0
  732. package/tests/patches/fixtures/middleware_v0.9.1.py +5057 -0
  733. package/tests/patches/fixtures/middleware_v0.9.2.py +5120 -0
  734. package/tests/patches/fixtures/retrieval_v0.9.1.py +2684 -0
  735. package/tests/patches/fixtures/retrieval_v0.9.2.py +2700 -0
  736. package/tests/patches/test_fix_attached_files_position.py +118 -0
  737. package/tests/patches/test_fix_large_tool_args.py +130 -0
  738. package/tests/patches/test_fix_large_tool_results.py +531 -0
  739. package/tests/patches/test_fix_skip_embedding_chat_files.py +160 -0
  740. package/tests/patches/test_fix_skip_rag_files_native_fc.py +120 -0
  741. package/tests/patches/test_fix_tool_loop_errors.py +128 -0
  742. package/tests/security/test_path_traversal_app.py +132 -0
  743. package/tests/security/test_path_traversal_docker.py +36 -0
  744. package/tests/security/test_path_traversal_settings.py +87 -0
  745. package/tests/security/test_safe_path_util.py +166 -0
  746. package/tests/security/test_xss_preview.py +46 -0
  747. package/tests/test-default-model-resolution.py +136 -0
  748. package/tests/test-docker-image.sh +358 -0
  749. package/tests/test-list-subagent-models.sh +421 -0
  750. package/tests/test-mcp-endpoint-live.sh +92 -0
  751. package/tests/test-mcp-native-surface.sh +213 -0
  752. package/tests/test-no-cyrillic.sh +135 -0
  753. package/tests/test-opencode-error-mapping.py +130 -0
  754. package/tests/test-pr88-skills.sh +305 -0
  755. package/tests/test-project-structure.sh +202 -0
  756. package/tests/test-single-user-mode.sh +269 -0
  757. package/tests/test-skill-no-hardcoded-models.sh +65 -0
  758. package/tests/test-subagent-cli-surface.py +137 -0
  759. package/tests/test-subagent-runtime.sh +109 -0
  760. package/tests/test_codex_toml_converter.py +204 -0
  761. package/tests/test_default_resolver_no_legacy_global.py +159 -0
  762. package/tests/test_filter.py +648 -0
  763. package/tests/test_init_sh_unchanged.sh +49 -0
  764. package/tests/test_opencode_alias_map_drop.py +144 -0
  765. package/tests/test_requirements.py +91 -0
  766. package/tests/test_subagent_docstring.py +193 -0
  767. package/tests/test_tools.py +34 -0
  768. package/vendor/extract-text/README.md +46 -0
  769. package/vendor/extract-text/extract-text +0 -0
@@ -0,0 +1,80 @@
1
+ <!-- SPDX-License-Identifier: FSL-1.1-Apache-2.0 -->
2
+ <!-- Copyright (c) 2025 Open Computer Use Contributors -->
3
+
4
+ ---
5
+ status: draft
6
+ last-reviewed: 2026-06-03
7
+ owner: "@Wide-Moat/architects"
8
+ applies-to: next/v1
9
+ compliance: []
10
+ threat-model: 06-threat-model.md
11
+ contract: contracts/mcp/2025-06-18/ocu-constraints.schema.json
12
+ adr: []
13
+ ---
14
+
15
+ The agent-facing inbound terminator: it authenticates the MCP caller, validates the tool-call, and hands a session request to the Control/operator API. Audience: engineers and security reviewers implementing or auditing the inbound MCP edge.
16
+
17
+ # Component-01: MCP gateway
18
+
19
+ ## Purpose
20
+
21
+ Terminates inbound MCP tool-calls and authenticates the caller, then forwards a metadata-only session request to the Control/operator API ([`05-c4-container.md`](../05-c4-container.md) §3). It is a Conformist to the public MCP revision and runs no agent loop, so the calling client owns the loop and the model; the gateway holds no caller token past the request, no upstream credential, and no lifecycle or kill-switch route.
22
+
23
+ ## Boundaries
24
+
25
+ Intra-container, the gateway is one process with three internal stages on each request:
26
+
27
+ | Internal stage | What it does |
28
+ |---|---|
29
+ | transport listener | terminates the MCP connection and validates the bearer audience |
30
+ | schema validation | applies the MCP base schema, then the OCU constraint profile |
31
+ | forwarding | issues a service-identity request to the Control/operator API |
32
+
33
+ The inbound caller edge, the gateway→Control/operator API edge, and the gateway→Audit pipeline fan-in are the boundaries `05-c4-container.md` §4 names (their `F1`/`F5`/`F10` flow labels are defined in [`05-c4-container.md`](../05-c4-container.md) §4); this spec adds only which internal stage terminates each.
34
+
35
+ Owned state: none that outlives a request. The gateway holds the in-flight request, the negotiated protocol revision for the connection, and its own service-identity signing material; it persists no session registry (that is the Control/operator API), no caller token after the response, and no customer payload. It provably does NOT hold an upstream credential, a Custody credential lease, a Storage-mount handle, the session denylist, or any route that resolves to a lifecycle or kill-switch operation — the operator surface sits in a separate container reachable only on operator-only ingress ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §8).
36
+
37
+ Token classes ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §8 owns the taxonomy): the gateway validates the inbound external bearer as a relying party, presents a Generic internal token on the forward to the Control/operator API, and mints or holds neither a Session JWT nor a Custody credential lease. The wire contract is the OCU constraint profile over MCP revision 2025-06-18 ([`ocu-constraints.schema.json`](../../../contracts/mcp/2025-06-18/ocu-constraints.schema.json)); it is a conform-not-define overlay, so field types, the error envelope, and the numeric caps live in the schema. The schema does not encode three facts: the gateway terminates the MCP socket and applies the base schema before the profile; the bearer is carried on the transport, never in the JSON-RPC body or URI query; and the caller token is never forwarded onto the Control/operator API leg or into the sandbox.
38
+
39
+ ## Invariants
40
+
41
+ Each holds independent of the caller and is falsifiable by the named check.
42
+
43
+ - Every inbound tool-call is validated against the MCP base schema then the OCU profile before any forward, and an unknown field or out-of-bound payload is rejected pre-buffer with a structured deny, never partially acted on (schema-validation + property-test, NFR-SEC-51, NFR-SEC-46).
44
+ - The bearer must name this MCP server in its audience claim or the request is refused with the relying-party challenge; identity is never read from the request body (schema-validation + unit-test, NFR-SEC-09).
45
+ - The caller bearer never appears on the forward leg, in a forwarded argument, or in any path reaching the sandbox; the forward carries only the gateway's own service identity (code-path audit + integration-test, NFR-SEC-09, NFR-SEC-26).
46
+ - No gateway code path resolves to a lifecycle, denylist, or kill-switch route, and no rendered deploy manifest grants the gateway a network route to the operator ingress on either shelf (IaC-policy assertion, NFR-SEC-52).
47
+ - Outbound errors and discovery responses are size-bounded and carry a stable reason class plus a correlation id only — never a session id, `container_name`, internal host/route, or stack detail (schema-validation + property-test, NFR-SEC-51).
48
+ - The negotiated protocol revision is pinned per connection; a request whose `MCP-Protocol-Version` is missing or unnegotiable is rejected rather than silently downgraded (schema-validation + unit-test, NFR-IC-04).
49
+ - Tool execution is serialized per session by default; parallelism is opt-in per skill (integration-test, NFR-IC-05).
50
+ - The gateway holds at most a configured number of open connections per audience-validated caller; excess is refused, not queued, and a single caller cannot consume more than its configured share of the listener fd table (chaos-test, NFR-SEC-53).
51
+
52
+ ## Failure modes
53
+
54
+ Each row traces to one P1 STRIDE row in [`06-threat-model.md`](../06-threat-model.md) §3.2 and repeats that row's controlling NFR; fail-closed is the default on every authentication and forward boundary. A1 is the in-sandbox guest; A2 is the external caller (the reaching actor on the gateway's P1 element).
55
+
56
+ | Trace | Reaching actor | What goes wrong | Recovery behaviour | Controlling NFR |
57
+ |---|---|---|---|---|
58
+ | P1-S1 | A2 | Replayed, forged, or wrong-audience bearer presented to open or address sessions | Validate as relying party; refuse with the resource-metadata challenge | NFR-SEC-09 |
59
+ | P1-S2 | A2 | Gateway service identity escalated on the forward so the Control/operator API treats the request as more privileged | The forward carries the gateway service principal only, which holds no operator scopes | NFR-SEC-26 |
60
+ | P1-T1 | A2 | On-path rewrite of tool-call parameters in flight | Validate audience and schema before acting; downstream authority is the host-derived identity, not the body | NFR-SEC-33 |
61
+ | P1-T2 | A2 | Forwarded body claims another tenant's `session_id`/`container_name` to bind or read a session it does not own | The body id is a hint cross-checked host-side; the Control/operator API derives the binding, so a forged id grants no reach | NFR-SEC-43 |
62
+ | P1-R1 | A2 | Caller denies issuing a tool-call/session-create; no independent record attributes the action | Emit an OCSF event on fan-in per terminated request with the validated caller identity | NFR-SEC-03 |
63
+ | P1-I1 | A2 | Verbose MCP errors or discovery leak session ids, `container_name`, tenant ids, or the operator surface | Emit a stable reason class + correlation id only, size-bounded; discovery exposes only the declared tool surface | NFR-SEC-51 |
64
+ | P1-D1 | A2 | Flood of the MCP surface exhausts gateway connections/CPU and pressures the lifecycle plane via the forward | Per-caller connection/fd ceiling refuses excess; the separate runnable unit means saturation cannot reach operator ingress or the kill-switch | NFR-COST-06, NFR-SEC-01, NFR-SEC-53 |
65
+ | P1-E2 | A2 | Caller invokes a tool or action beyond its authorization; the gateway authenticates but does not yet decide per-action authz | Audience-validated authN bounds who reaches the surface; host-attested identity blocks cross-session addressing downstream; per-action authz is the residual | NFR-SEC-49 |
66
+
67
+ Residual, by [`06-threat-model.md`](../06-threat-model.md) §5 register: per-action authorization (P1-E2) is specified by NFR-SEC-49 but not yet enforced at the gateway — tracked at [#187](https://github.com/Wide-Moat/open-computer-use/issues/187). The identifier-minimization measurement behind P1-I1/P1-R1 is tracked at [#149](https://github.com/Wide-Moat/open-computer-use/issues/149). The gateway↛operator network separation that bounds P1-S2 and P1-D1 is verified by the NFR-SEC-52 IaC-policy assertion; the gateway is the agent-path side of the two-container split whose escalation row (P2-E1) is owned with the Control/operator API.
68
+
69
+ ## Operational concerns
70
+
71
+ Config surface: the inbound listener bind and transport, the bearer relying-party metadata (issuer, audience, resource-metadata URL), the pinned MCP revision, the per-caller connection/fd ceiling and per-tenant calls-min quota (NFR-COST-06, NFR-SEC-53), and the gateway's own caps on error/result/argument size — each an enforced default the operator may retune within the NFR-SEC-46/51 floor. Observability: the gateway emits OCSF on the fan-in flow for every terminated request with the validated caller identity, and an OCSF rejection event on a connection-ceiling refusal ([`audit/audit-fanin`](../../../contracts/audit/audit-fanin.asyncapi.yaml), NFR-SEC-03). Scaling axis: single instance per deployment (not per session); capacity is bounded by the per-caller ceiling and the MCP request success-rate target (NFR-PERF-01). Upgrade/rotation: the gateway carries no semver — its revision is the date string negotiated on `initialize`, and a peer that cannot negotiate the revision is the breaking signal rather than an HTTP deprecation header (NFR-IC-04); the service-identity signing key rotates on the inter-component identity cadence ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §8).
72
+
73
+ Shelf delta ([`05-c4-container.md`](../05-c4-container.md) §5): the minimal shelf runs the gateway as a single co-located process whose service identity is a host-local signing key and whose caller authN is a host-rooted local credential; the full shelf schedules a single instance whose service identity is a customer-PKI workload identity and whose caller authN is the customer-IdP-asserted relying-party flow (NFR-COMP-29). The invariants above are boundary properties and hold on both shelves; only the identity substrate and listener scheduling change.
74
+
75
+ ## Open questions
76
+
77
+ 1. Does NFR-IC-04 bind only the Control/operator API and internal RPC, leaving the MCP edge governed solely by date-revision negotiation, or does it need an explicit MCP-edge clause? — [#207](https://github.com/Wide-Moat/open-computer-use/issues/207).
78
+ 2. Per-action / per-tool authorization at the gateway (deny-by-default keyed on caller, tool name, action parameters) — [#187](https://github.com/Wide-Moat/open-computer-use/issues/187).
79
+ 3. Outbound error/discovery identifier-minimization and size-bound enforcement at the gateway decoder — [#149](https://github.com/Wide-Moat/open-computer-use/issues/149).
80
+ 4. Whether the per-session sequential-execution serializer (the NFR-IC-05 carrier, today a gateway behaviour with no wire field) needs its own versioned conformance fixture so opt-in parallelism is testable independently of the MCP profile ([#239](https://github.com/Wide-Moat/open-computer-use/issues/239)).
@@ -0,0 +1,80 @@
1
+ <!-- SPDX-License-Identifier: FSL-1.1-Apache-2.0 -->
2
+ <!-- Copyright (c) 2025 Open Computer Use Contributors -->
3
+
4
+ ---
5
+ status: draft
6
+ last-reviewed: 2026-05-31
7
+ owner: "@Wide-Moat/architects"
8
+ applies-to: next/v1
9
+ compliance: []
10
+ threat-model: 06-threat-model.md
11
+ contract: null
12
+ adr: [0004]
13
+ ---
14
+
15
+ The operator-facing lifecycle terminator: it owns session lifecycle, quota, the session denylist, and the kill-switch, reachable only on operator/lifecycle ingress and never from the agent-facing MCP surface. Audience: engineers wiring the operator plane or auditing the kill-switch path.
16
+
17
+ # Component-02: Control / operator API
18
+
19
+ ## Purpose
20
+
21
+ Owns session lifecycle, quota, the session denylist, and the kill-switch ([`05-c4-container.md`](../05-c4-container.md) §3). It is the operator side of the Control plane split into two runnable units so the kill-switch is unreachable from the agent path by network policy rather than an in-process guard; it is the sole author of the session denylist that the Egress trust-edge reads and that the Control plane checks host-side on every Compute-plane control RPC (`F6`) ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §7).
22
+
23
+ ## Boundaries
24
+
25
+ Intra-container, this is one process with three internal components behind a single operator/lifecycle ingress that is a distinct deployable from the MCP gateway:
26
+
27
+ | Internal component | What it does |
28
+ |---|---|
29
+ | lifecycle controller | terminates session create/status/destroy (gateway service identity) and operator session ops; host-dials the Session sandbox to set up and tear down |
30
+ | denylist + kill-switch authority | terminates operator force-kill, denylist edits, and signed SOAR revoke; authors the denylist and signals a host-initiated stop |
31
+ | quota accountant | checks per-caller create-rate and per-tenant counters on create; refuses excess |
32
+
33
+ The operator/lifecycle ingress, the SOAR-revoke ingress, the gateway→Control session set-up edge, the Control→Session sandbox host-dial, and the Control→Audit fan-in are the boundaries `05-c4-container.md` §4 names (their `F2`/`F4`/`F5`/`F6`/`F10` flow labels are defined in [`05-c4-container.md`](../05-c4-container.md) §4); this spec adds only which internal component terminates each.
34
+
35
+ Owned state: the session registry (live sessions, their `container_name` binding, tenant, quota counters) and the denylist (kill-switch state), of which this container is sole custodian — no other component can mutate either, and the guest holds no handle that reaches them. It provably does NOT hold an upstream credential or backend storage key (the upstream credential reaches the Egress trust-edge over Envoy SDS; the backend storage key sits with the Storage broker, [`02-trust-boundaries.md`](../02-trust-boundaries.md) §2), and holds no Storage-mount handle.
36
+
37
+ Token classes ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §8 owns the taxonomy and TTLs): this container mints the Session JWT (per-session, bound to `container_name`) toward the Session sandbox on the host-dialled control channel, accepts a Generic internal token authenticating the inbound gateway service identity on session set-up, and accepts an operator credential on ingress (the operator-auth substrate is fixed by [ADR-0004](../adr/0004-operator-authentication-substrate.md)). The wire surface is unfrozen: the operator REST and SOAR-revoke surfaces (OpenAPI 3.1) and the gateway→Control session set-up RPC (Protobuf/gRPC) are OCU-`define` in [`08-contracts.md`](../08-contracts.md) §1, but their schema files are not yet built ([#205](https://github.com/Wide-Moat/open-computer-use/issues/205)), so `contract: null`. Two listeners back this container — operator/lifecycle ingress and gateway service-identity ingress; the kill-switch route exists only on the former. The customer-IdP assertion on ingress is relying-party, not an OCU-defined surface.
38
+
39
+ ## Invariants
40
+
41
+ Each holds independent of the caller and is falsifiable by the named check. Cross-cutting properties (zone membership, in-transit encryption, retention floor, isolation tier) are Layer 3 and not restated.
42
+
43
+ - No MCP-surface route resolves to a lifecycle, denylist, or kill-switch route, and no rendered deploy manifest grants the gateway a network route to the operator ingress on either shelf (IaC-policy assertion, NFR-SEC-52).
44
+ - The kill-switch and revoke path holds its SLA while the control plane is saturated, including a flood on the operator/SOAR ingress itself; the lifecycle/revoke route carries reserved capacity or admission priority distinct from the create path (chaos test with an adversarial concurrent-load dimension, NFR-SEC-55, with the ≤30 s p99 value owned by NFR-SEC-01).
45
+ - A body-supplied session/tenant/`container_name` id is a hint, never the authority; the binding the host acts on (the host-dial, the registry write) is host-derived, so a gateway or guest naming another session's id cannot bind or address it (integration-test: forge-another-session attempt fails, NFR-SEC-43).
46
+ - The gateway service identity reaching this container carries no operator scope; force-kill, denylist edit, and quota override are unreachable with that audience (unit + integration-test on the audience-to-route map, NFR-SEC-26).
47
+ - Every privileged operator/SOAR action in the NFR-SEC-45 enumerated set emits a chain-linked OCSF event before acknowledgement, and the action is denied if the audit write fails (fail-closed); the enumerated set is the versioned fixture owned by NFR-SEC-45, with system-initiated lifecycle transitions owned by NFR-SEC-72 (per-release integration-test driving every action + a negative test asserting deny on audit-sink failure, NFR-SEC-45).
48
+ - Per-caller create-rate and per-tenant quota are enforced before a session is created; excess is refused, not queued, and agent-side create flooding cannot starve the operator/revoke route because the two ingresses are distinct (quota integration + connection-flood chaos test, NFR-COST-06, NFR-SEC-53).
49
+ - All TTL and revocation windows (Session JWT, denylist propagation) are computed against a monotonic clock immune to wall-clock setback; a setback ≥ a window neither extends a token nor defers a revoke (red-team clock-rollback harness, NFR-SEC-48).
50
+
51
+ ## Failure modes
52
+
53
+ Each row traces to one P2 STRIDE row in [`06-threat-model.md`](../06-threat-model.md) §3 and repeats that row's controlling NFR; fail-closed is the default on the denylist, revoke, and audit-write boundaries. A1 is the in-sandbox guest; A2 is the external caller / gateway service identity; A3 is the operator/SOAR principal.
54
+
55
+ | Trace | Reaching actor | What goes wrong | Recovery behaviour | Controlling NFR |
56
+ |---|---|---|---|---|
57
+ | P2-E1 | A2, A1 | Agent-path principal probes for an operator or kill-switch route | No lifecycle/kill-switch route resolves; gateway→operator-ingress reachability is denied at deploy time and a missed route fails CI, not runtime | NFR-SEC-52 |
58
+ | P2-T2 | A1 | Guest stalls or drops the host-dialled control RPC to defeat the stop | The denylist is read host-side and the kill-switch is a host-initiated stop, not a cooperative guest action; an unreachable channel grants no new authority (fail-closed) | NFR-SEC-01 |
59
+ | P2-D1 | A2, A1 | Concurrent flood of session-create and operator/SOAR calls aims to starve revoke | The create path sheds at the per-caller/per-tenant quota and fails-closed; the revoke route holds reserved capacity so the kill-switch stays within SLA, with RTO/RPO the post-failure backstop | NFR-SEC-55, NFR-REL-01 |
60
+ | P2-R1 | A3, A2 | Operator force-kill / denylist edit / quota override leaves no independent record | The action is denied if its audit event fails to write; it does not take effect un-recorded | NFR-SEC-45 |
61
+ | P2-R2 | A2 | SOAR revoke disputed or replayed | The call is verified by signature against the SOAR principal before acting and emits an OCSF event bound to that principal; an unverifiable call is rejected | NFR-COMP-27, NFR-SEC-45 |
62
+ | P2-I1 | A2, A3 | Registry/quota enumeration across tenants | Audience-scoping returns only the caller's own sessions and host-attested binding blocks cross-session reads; the control plane carries no customer payload | NFR-IC-04 |
63
+
64
+ Residual, by [`06-threat-model.md`](../06-threat-model.md) §5 register: the stop-SLA accounting behind P2-T2 assumes a trustworthy host clock — trusted-time theme, [#185](https://github.com/Wide-Moat/open-computer-use/issues/185). Saturation/spill behaviour and a measurable containment target for P2-D1 fold into the resource-exhaustion theme, [#188](https://github.com/Wide-Moat/open-computer-use/issues/188). The mandatorily-audited action set behind P2-R1/P2-R2 is the privileged-operator-audit theme tracked at [#186](https://github.com/Wide-Moat/open-computer-use/issues/186). The no-customer-payload gate behind P2-I1 is not yet a measurable target, [#149](https://github.com/Wide-Moat/open-computer-use/issues/149).
65
+
66
+ The denylist this container authors also gates the Egress trust-edge: a revoked session is refused lease injection at the edge (the deny-signal half of [`02-trust-boundaries.md`](../02-trust-boundaries.md) §7). That enforcement behaviour lives in the Egress trust-edge spec; here the invariant is only sole authorship of the denylist the edge reads.
67
+
68
+ ## Operational concerns
69
+
70
+ Config surface: the operator/lifecycle ingress listener and the gateway service-identity listener are distinct network endpoints (the NFR-SEC-52 separation); per-caller create-rate, per-tenant concurrent-session and calls/min ceilings (NFR-COST-06), and the reserved lifecycle/revoke capacity (NFR-SEC-55) are the principal knobs. Observability: this container emits OCSF on the audit fan-in for session create/destroy, every enumerated privileged action (NFR-SEC-45), and quota rejections, into the hash-chained pipeline ([`audit/audit-fanin`](../../../contracts/audit/audit-fanin.asyncapi.yaml), NFR-SEC-03); the audit-write is on the critical path of a privileged action (fail-closed), not a side-channel. Scaling axis: one instance per deployment (not per session); the single-instance minimal shelf is in scope for the kill-switch-under-saturation target (NFR-SEC-55), so the capacity model reserves admission priority for the revoke route rather than scaling out, and RTO/RPO of this plane is NFR-REL-01. Upgrade/rotation: the RPC surface (session create/destroy/exec/fs) is versioned — a breaking change requires a major version plus deprecation header, CI-enforced by `buf breaking` / `oasdiff` (NFR-IC-04, [`08-contracts.md`](../08-contracts.md) §4); Session JWT rotation is mint-fresh-before-expiry, not extension, on the JWT TTL window in [`02-trust-boundaries.md`](../02-trust-boundaries.md) §8.
71
+
72
+ Shelf delta ([`05-c4-container.md`](../05-c4-container.md) §5): the minimal shelf co-locates this container with a host-rooted local operator credential and a host-local Session-JWT signing key; the full shelf schedules it with a customer-IdP-asserted operator identity (NFR-COMP-29) and a customer-PKI-rooted signer. The invariants above are boundary properties and hold on both shelves; only the operator-auth substrate and the JWT signer change, never the gateway↛operator separation, the host-attested binding, or the fail-closed audit-write. Retention of the audit events this container emits is the platform floor owned by the Audit pipeline (NFR-COMP-01). The operator-auth substrate is fixed by [ADR-0004](../adr/0004-operator-authentication-substrate.md).
73
+
74
+ ## Open questions
75
+
76
+ 1. Minimum scope of the gateway's internal token on the session set-up edge, and per-tool/per-action authorization on operator actions — [#187](https://github.com/Wide-Moat/open-computer-use/issues/187).
77
+ 2. Measurable no-customer-payload gate on the control plane — [#149](https://github.com/Wide-Moat/open-computer-use/issues/149).
78
+ 3. Saturation/spill behaviour and a measurable containment target for the create and operator/SOAR ingress under sustained adversarial load — [#188](https://github.com/Wide-Moat/open-computer-use/issues/188).
79
+ 4. Trusted-time floor for Session-JWT TTL and denylist-propagation windows — [#185](https://github.com/Wide-Moat/open-computer-use/issues/185).
80
+ 5. Operator-auth substrate (PAM-JIT integration, full vs minimal shelf) is fixed by [ADR-0004](../adr/0004-operator-authentication-substrate.md); the multi-party-approval residual is tracked at [#225](https://github.com/Wide-Moat/open-computer-use/issues/225).
@@ -0,0 +1,104 @@
1
+ <!-- SPDX-License-Identifier: FSL-1.1-Apache-2.0 -->
2
+ <!-- Copyright (c) 2025 Open Computer Use Contributors -->
3
+
4
+ ---
5
+ status: draft
6
+ last-reviewed: 2026-06-03
7
+ owner: "@Wide-Moat/architects"
8
+ applies-to: next/v1
9
+ compliance: []
10
+ threat-model: 06-threat-model.md
11
+ contract: [contracts/storage/mount-config.schema.json, contracts/storage/file-ops.schema.json, contracts/storage/file-artifact-api.schema.json]
12
+ adr: [0002, 0010, 0011]
13
+ ---
14
+
15
+ The host-side object-store client that custodies the backend credential and resolves file authorization for the guest mount and an external data-plane client, so neither holds a backend key. Audience: engineers and security reviewers implementing or auditing the storage surface.
16
+
17
+ # Component-04: Storage broker
18
+
19
+ ## Purpose
20
+
21
+ Custodies the backend object-store credential and resolves file authorization for two callers — the guest mount and an external data-plane client ([`05-c4-container.md`](../05-c4-container.md) §3). Both faces are components inside one container, sharing one backend credential and one storage-lane backend leg ([NFR-SEC-85](../manifesto/02-nfrs.md)); the `downloadable` axis is resolved at read on both faces, not stamped at write.
22
+
23
+ ## Boundaries
24
+
25
+ Intra-container, the broker is one process whose two faces call a shared authorization resolver and a single object-store client. The inter-container edges — the broker→sandbox mount, the broker→edge→backend leg, the broker→audit fan-in, and the data-plane-client→broker crossing — are the boundaries [`05-c4-container.md`](../05-c4-container.md) §4 names (their `F7`/`F9`/`F10`/`F11` flow labels are defined in [`05-c4-container.md`](../05-c4-container.md) §4); this spec adds only the intra-container split below.
26
+
27
+ ```mermaid
28
+ flowchart LR
29
+ SM[South-face mount adapter]
30
+ NF[North-face file/artifact API + SPA + preview-render]
31
+ AUTHZ[Three-axis authz resolver]
32
+ OSC[Object-store client + backend signer]
33
+ SM --> AUTHZ
34
+ NF --> AUTHZ
35
+ AUTHZ --> OSC
36
+ ```
37
+
38
+ The south-face mount adapter terminates the `filesystem_id`-scoped file-operation interface from the guest; the north-face component terminates the file/artifact API plus the authenticated SPA and the preview-render path. The files surface is one entry in the data-plane UI's descriptor-driven view list ([ADR-0002](../adr/0002-session-view-descriptor.md)); the broker serves that entry, while the descriptor shell and the deferred live-view surfaces sit outside this container. Both call one authz resolver, which calls one object-store client — the sole component that speaks the backend protocol and signs every backend request. The substrate under the mount (FUSE / virtio-fs / 9p) and the message-set transport are component-spec choices, not contract.
39
+
40
+ ### Owned state
41
+
42
+ | Owns (sole custodian) | Provably does NOT hold |
43
+ |---|---|
44
+ | The backend object-store credential | No upstream-API credential (that reaches the Egress trust-edge over Envoy SDS) |
45
+ | The `filesystem_id` → backend prefix mapping | No kill-switch state and no route to the denylist (those are the Control / operator API) |
46
+ | Per-object `downloadable` disposition, resolved at read | No second outbound path; a direct broker→backend dial bypassing the edge is forbidden (NFR-SEC-16) |
47
+ | The north-face first-party session minted after embed-token verify | No long-lived caller identity: it verifies a peer-minted embed token, it does not issue it |
48
+
49
+ The guest holds only the Storage-mount handle (a `filesystem_id`); the data-plane client presents only an embed token. The Storage-mount handle is canonical in [`02-trust-boundaries.md`](../02-trust-boundaries.md) §8 (session-scoped); the embed token is a peer-minted relying-party credential, not an OCU §8 class — its `exp` is fixed by NFR-SEC-82 — referenced, not restated. The backend signature is produced once, in the object-store client; the egress edge forwards the broker-signed leg on a storage-dedicated lane allow-list-only without TLS termination ([NFR-SEC-85](../manifesto/02-nfrs.md)). The frozen field types, error envelope, and embed/CSP/CSRF wire detail live in the three bound schema files ([`mount-config`](../../../contracts/storage/mount-config.schema.json), [`file-ops`](../../../contracts/storage/file-ops.schema.json), [`file-artifact-api`](../../../contracts/storage/file-artifact-api.schema.json)).
50
+
51
+ ## Invariants
52
+
53
+ Each rule holds independent of the caller and is falsifiable by the named check. Cross-cutting properties (zone membership, in-transit encryption, retention floor, runtime tier) are Layer 3 and excluded here.
54
+
55
+ 1. No file-op or API call resolves a path or object handle outside the request's host-attested `filesystem_id` prefix; traversal, symlink, absolute-path, and URL-shaped handles are rejected before any backend call (property-test, NFR-SEC-25).
56
+ 2. No request the guest or data-plane client issues names a backend object directly; the broker maps a file-op verb / API intent to a request signed with its own credential, and a caller-supplied session/tenant id is a hint cross-checked against host-attested identity, never the identity itself (property-test, NFR-SEC-43).
57
+ 3. `downloadable` is resolved broker-side at read on both faces from the host-attested session, never from a client-supplied claim; a non-downloadable object is readable in-session but yields no egress-eligible artifact, and `intent=preview` stays read-only and non-downloadable regardless of stored tag (property-test, NFR-SEC-73).
58
+ 4. Three-axis authorization (scope `filesystem_id` + intent `read`/`write`/`preview` + downloadable) is re-derived broker-side per request, deny-by-default keyed on the authenticated caller; a `preview`-authorized caller cannot invoke `download`/`write` (property-test, NFR-SEC-49).
59
+ 5. A north-face inbound body above the configured ceiling is rejected pre-buffer, never partially staged; archive bodies are validated (uncompressed-total / entry-count / ratio / traversal / symlink) before extraction and content-classified on ingest before becoming mount-visible (schema-validation + property-test, NFR-SEC-78, NFR-SEC-80, NFR-SEC-81).
60
+ 6. The north face accepts no request without a signature-valid, in-audience, unexpired embed token before any session state is set, then 401s a missing/invalid session with no anonymous fallback, requires a server-validated CSRF token on every state-mutating call, and sends `CSP: frame-ancestors` from the per-deployment allowlist on every UI/artifact response (schema-validation, NFR-SEC-82, NFR-SEC-83, NFR-SEC-84). The header values are fixed in [`08-contracts.md`](../08-contracts.md) §3 and the bound schema.
61
+ 7. No OCU upstream secret crosses to the browser; the embed token is peer-minted and the backend credential never leaves the object-store client (unit-test + property-test, NFR-SEC-82).
62
+ 8. Every file-activity on either face emits an OCSF File System Activity event into the hash-chained pipeline before the operation is acknowledged; an audit-write failure denies the operation (fail-closed) (unit-test, NFR-SEC-79).
63
+ 9. For a multi-tenant deployment the broker is instantiated per tenant — one broker principal per tenant filesystem scope; a multiplexed broker is admitted only on a single-tenant `trusted_operator` shelf (IaC-policy assertion, NFR-SEC-76).
64
+ 10. A long-lived host-local backend credential is admitted only where `workload_trust_profile = trusted_operator` and the deployment is single-tenant; any other profile or a multi-tenant deployment requires the STS-scoped-per-session credential, and admission rejects otherwise (per-profile admission test, NFR-SEC-60).
65
+
66
+ ## Failure modes
67
+
68
+ Each row traces to one P4 STRIDE row in [`06-threat-model.md`](../06-threat-model.md) §3; the Trace column points at the row for threat detail, the Recovery column carries the container-internal contract. The reaching actor is A1 (in-sandbox guest) on the south/backend legs and A2 (external data-plane client) on the north face. Fail-closed is the default on every authz, audit, and ingest boundary.
69
+
70
+ | Failure | Trace | Recovery behaviour |
71
+ |---|---|---|
72
+ | Guest crafts traversal/symlink/oversized file-op to escape the prefix | P4-T1 (NFR-SEC-25 + SEC-46) | Resolve inside the host-attested prefix and reject pre-backend; oversized write rejected pre-buffer at the max-object ceiling, never partially staged. |
73
+ | Cross-session read of leftover content on a reused mount, or list beyond prefix | P4-I2 (NFR-SEC-54 + SEC-13 + SEC-64 + SEC-25 + SEC-73) | Erase-before-reuse zeroizes a recycled substrate before a session-2 handle binds (NFR-SEC-54), the per-session DEK is destroyed on session end (NFR-SEC-13), page-cache/backend residue is dropped before the next session runs (NFR-SEC-64), and list/read stays prefix-confined (NFR-SEC-25 + SEC-73). |
74
+ | Guest floods file-ops / huge writes / fd exhaustion against a shared broker | P4-D1 (NFR-SEC-46) | Per-session file-ops/s, in-flight-bytes, and fd ceilings throttle fail-closed, not broker-wide degradation. Residual: resource-exhaustion theme, [#188](https://github.com/Wide-Moat/open-computer-use/issues/188). |
75
+ | Guest drives backend traffic to exhaust STS quota / blow up backend cost | P4-D2 (NFR-SEC-85 + SEC-16) | A network backend engine's traffic traverses the storage-dedicated lane ([NFR-SEC-85](../manifesto/02-nfrs.md)) as one observable destination and the bypass dial is forbidden, so the leg is policy-gated; a local-volume engine ([ADR-0010](../adr/0010-storage-backend-pluggable-adapter.md)) has no network leg, so per-session file-op ceilings (P4-D1) are the gate. Residual: per-session backend rate ceiling — resource-exhaustion theme, [#188](https://github.com/Wide-Moat/open-computer-use/issues/188). |
76
+ | Guest smuggles a backend key/prefix through a file-op argument (confused deputy) | P4-E1 (NFR-SEC-25 + SEC-43 + SEC-76) | The broker signs with its own credential against the host-attested mapping; broker-per-tenant bounds the deputy. Residual: per-action authz, [#187](https://github.com/Wide-Moat/open-computer-use/issues/187). |
77
+ | Broker opens a direct backend dial bypassing the storage lane | P4-E2 (NFR-SEC-85 + SEC-16) | The bypass dial is refused; a network backend engine's leg must traverse the storage-dedicated lane ([NFR-SEC-85](../manifesto/02-nfrs.md)) — out-of-process from the broker, so a compromised broker cannot silence it — while a local-volume engine ([ADR-0010](../adr/0010-storage-backend-pluggable-adapter.md)) opens no network leg to bypass. Residual: the lane is pass-through, so deep content DLP on legitimately-written objects stays broker-side (NFR-SEC-81) — content-blind theme, [#182](https://github.com/Wide-Moat/open-computer-use/issues/182). |
78
+ | Data-plane client replays / forges / frames the embed token | P4-S3 (NFR-SEC-82 + SEC-83) | Verify before minting a first-party session; `frame-ancestors` allowlist denies cross-origin framing. Residual: no replay-binding (`jti`/nonce) within TTL — embed-token replay, [#217](https://github.com/Wide-Moat/open-computer-use/issues/217). |
79
+ | Cross-site forgery against the first-party cookie / token leak via `Referer` | P4-T3 (NFR-SEC-84 + SEC-82) | First-party cookie with server-validated CSRF token on every mutating call; 401 on missing/invalid session. Residual: token-pattern + `exp`-in-URL hardening, [#187](https://github.com/Wide-Moat/open-computer-use/issues/187). |
80
+ | Forged/swapped id read, preview leak via `postMessage('*')`, or `downloadable=false` bytes shipped | P4-I3 (NFR-SEC-49 + SEC-73 + SEC-83) | Three-axis authz re-derived from the host-attested session; preview read-only and non-downloadable; framing closed by the allowlist. Residual: per-object authz granularity, [#187](https://github.com/Wide-Moat/open-computer-use/issues/187); preview-render parser isolation, [#218](https://github.com/Wide-Moat/open-computer-use/issues/218). |
81
+ | North-face inbound-byte flood: pre-auth verify-cost, oversized upload, zip-bomb preview | P4-D3 (NFR-SEC-78 + SEC-80) | Body capped and rejected pre-buffer on a file/UI ingress distinct from the MCP listener; archive validated before extraction; content classified on ingest. Residual: pre-auth verify-cost flood — resource-exhaustion theme, [#188](https://github.com/Wide-Moat/open-computer-use/issues/188). |
82
+ | North-face upload/download/delete/preview later disputed | P4-R2 (NFR-SEC-79 + SEC-09) | OCSF File System Activity event per operation, fail-closed, under host-attested identity, before the response is issued. Residual: binding OCSF `actor` to the embed-asserted principal, [#181](https://github.com/Wide-Moat/open-computer-use/issues/181). |
83
+ | Client flips intent/tag to escalate `preview`→`download`/`write`, or crafted id drives SSRF/path escape | P4-E3 (NFR-SEC-49 + SEC-73 + SEC-80) | Lease scoped to verb + exact prefix, failing at the backend not only at policy; preview stays read-only; traversal/polyglot rejected pre-extraction. Residual: per-action granularity, [#187](https://github.com/Wide-Moat/open-computer-use/issues/187). |
84
+ | Compromised/impersonated broker reaches backend objects outside any live session | P4-S2 (NFR-SEC-25) | Full shelf: STS-scoped-per-session backend creds, so only the narrow per-session role is assumable. Residual: minimal-shelf host-local credential is broader (whole-bucket on broker-host compromise), admitted only under single-tenant `trusted_operator` (NFR-SEC-60) — called out by the shelf split (§Operational concerns). |
85
+ | Backend credential disclosed via process compromise / memory scrape / leak onto mount | P4-I1 (NFR-SEC-25 + SEC-33) | Credential host-side only, no object-store protocol toward the guest; full shelf narrows the held secret to an STS-scoped-per-session credential. Residual: minimal-shelf long-lived host-local credential, [#187](https://github.com/Wide-Moat/open-computer-use/issues/187). |
86
+
87
+ P4-S1 (south-face spoofing, NFR-SEC-43 + SEC-25), P4-T2 (backend leg in transit, NFR-SEC-05 + SEC-33), and P4-R1 (south-face attribution, NFR-SEC-43 + SEC-03 + SEC-25) are MITIGATED in §4 and are not live failure modes here.
88
+
89
+ ## Operational concerns
90
+
91
+ Config surface: the `filesystem_id`→prefix map, the north-face ingress binding (distinct from the MCP listener), the embed-token issuer/audience, the `frame-ancestors` per-deployment allowlist, and the inbound-body / archive ceilings (NFR-SEC-78, NFR-SEC-80; literal defaults fixed in [`08-contracts.md`](../08-contracts.md) §3). Observability is the OCSF File System Activity stream (invariant 8) plus per-session rate counters.
92
+
93
+ The container emits OCSF on the audit fan-in flow F10, fail-closed, per the audit contract ([`audit-fanin`](../../../contracts/audit/audit-fanin.asyncapi.yaml)) and NFR-SEC-03 / NFR-SEC-79 — both faces author the same File System Activity event class.
94
+
95
+ Scaling axis: per-tenant instantiation (NFR-SEC-76) — one broker principal per tenant filesystem scope. Whether that principal is also per-sandbox-host or per-deployment, and whether that changes the container diagram, is open ([#175](https://github.com/Wide-Moat/open-computer-use/issues/175)). Capacity is bounded by the per-session file-op and inbound-byte ceilings (NFR-SEC-46, NFR-SEC-78); a one-per-host broker serving many sessions is a shared DoS surface, which is why those ceilings are per-session, not per-broker.
96
+
97
+ Shelf delta (from [`05-c4-container.md`](../05-c4-container.md) §5): the minimal shelf holds a host-local backend credential, admitted only under `workload_trust_profile = trusted_operator` and single-tenant (NFR-SEC-60); the full shelf uses a customer-PKI workload identity with STS scoped per session (NFR-SEC-25). All invariants hold on both shelves; only the credential substrate and its blast radius (P4-S2 / P4-I1 residual) change. The backend engine is a pluggable adapter behind the object-store client ([ADR-0010](../adr/0010-storage-backend-pluggable-adapter.md)): a local-volume engine (the solo-reference, no network leg) and an S3 engine are both present from day one, and the egress-transit invariant applies only to a network engine's leg. The broker runs at the [NFR-SEC-02](../manifesto/02-nfrs.md) hardened-`runc` floor (seccomp BPF + Landlock + cap-drop ALL + read-only rootfs), profile-independent: it executes no agent-issued code, so it carries no `workload_trust_profile` tier axis (that axis is the sandbox's, [NFR-SEC-38](../manifesto/02-nfrs.md)) and no separate tier ladder. Its blast-radius is bounded by the credential substrate ([NFR-SEC-60](../manifesto/02-nfrs.md) / [NFR-SEC-25](../manifesto/02-nfrs.md)) and host-peer accept ([NFR-SEC-76](../manifesto/02-nfrs.md)), not by a runtime-tier ladder. The cardinality question — one broker per deployment or per sandbox host — stays open ([#175](https://github.com/Wide-Moat/open-computer-use/issues/175)).
98
+
99
+ ## Open questions
100
+
101
+ 1. Is the broker one instance per deployment or one per sandbox host, and does the answer change the container diagram? — [#175](https://github.com/Wide-Moat/open-computer-use/issues/175).
102
+ 2. Embed-token replay-binding (`jti`/nonce single-use or token↔channel binding) within the `exp` window — [#217](https://github.com/Wide-Moat/open-computer-use/issues/217).
103
+ 3. Preview-render parser isolation for untrusted artifact bodies on the north face — [#218](https://github.com/Wide-Moat/open-computer-use/issues/218).
104
+ 4. Per-action / per-object authorization granularity and minimum lease scope beyond resource-class — [#187](https://github.com/Wide-Moat/open-computer-use/issues/187).
@@ -0,0 +1,93 @@
1
+ <!-- SPDX-License-Identifier: FSL-1.1-Apache-2.0 -->
2
+ <!-- Copyright (c) 2025 Open Computer Use Contributors -->
3
+
4
+ ---
5
+ status: draft
6
+ last-reviewed: 2026-05-31
7
+ owner: "@Wide-Moat/architects"
8
+ applies-to: next/v1
9
+ compliance: []
10
+ threat-model: 06-threat-model.md
11
+ contract: contracts/exec/exec-channel.schema.json
12
+ adr: [0003]
13
+ ---
14
+
15
+ Internal design of the per-session execution container, for engineers implementing and auditing the guest agent and its host-side edges. The guest agent is the process that constitutes this container ([`05-c4-container.md`](../05-c4-container.md) §3): it is PID 1 and dies with the session.
16
+
17
+ # Component-05: Session sandbox
18
+
19
+ ## Purpose
20
+
21
+ Executes one session's tool-calls in an isolated runtime that holds no standing upstream secret and reaches the network only through the Egress trust-edge ([`05-c4-container.md`](../05-c4-container.md) §3). Spec scope is the intra-container split — the guest agent, the host-side exec supervisor, and the mount and egress edges the guest sees — not the inter-container flows Layer 6 already fixes.
22
+
23
+ ## Boundaries
24
+
25
+ Intra-container, the container is one process tree rooted at the guest agent (PID 1). Two host-side mediators sit outside the guest's network yet terminate the channels the guest uses: a per-session exec supervisor (terminates the exec WebSocket, spawns and reaps guest processes, bounds stdio) and the runtime supervisor (the user-space-kernel sentry on the gVisor tier, the VMM on the microVM tier, the host kernel on runc). The mount and egress edges are owned by other containers (Storage broker, Egress trust-edge); the guest holds only the handle and the route, never the credential.
26
+
27
+ | Direction | What crosses | Internal terminator | Note |
28
+ |---|---|---|---|
29
+ | host → guest | exec/PTY+CDP control union + stdin frames | exec supervisor (host-dialled; non-host peer dropped at accept) | one WebSocket per session; envelope frozen in [`exec/exec-channel`](../../../contracts/exec/exec-channel.schema.json) |
30
+ | guest → host | stdout/stderr binary frames + result/EOF | exec supervisor | length-prefixed, bounded per call (Invariants) |
31
+ | host → guest | Session JWT (selects session identity) | guest agent | Session JWT class, TTL per [`02-trust-boundaries.md`](../02-trust-boundaries.md) §8 |
32
+ | broker → guest | file-operation mount + Storage-mount handle | guest agent (mount client) | guest names file-op verbs, never the object-store protocol; substrate is named by role |
33
+ | guest → edge | outbound network leg | guest agent | guest carries no long-lived upstream secret on this leg; the edge attaches upstream authorization ([ADR-0005](../adr/0005-egress-credential-delivery-envoy-sds.md), [ADR-0007](../adr/0007-egress-auth-mechanism.md)) keyed on a presented scoped credential, never on the route's network origin; this route is the container's sole egress (invariant 4) |
34
+ | guest → audit | OCSF tool-call events (fan-in flow F10, defined in [`05-c4-container.md`](../05-c4-container.md) §4) | exec supervisor / runtime-monitor | host-authored, not guest-authored (Operational concerns) |
35
+
36
+ The inbound exec/PTY+CDP edge, the broker mount edge, and the outbound egress leg are the boundaries [`05-c4-container.md`](../05-c4-container.md) §4 names; their `F6`/`F7`/`F8` flow labels are defined in [`05-c4-container.md`](../05-c4-container.md) §4.
37
+
38
+ Owned state: the live process tree and its scratch/tmpfs, the per-process resource counters the exec supervisor keeps, and the guest's in-memory Session JWT and Storage-mount handle for the life of the session. It provably does NOT hold any upstream/backend credential, the Custody credential lease, the session denylist, or any kill-switch route — those sit host-side of the guest. The guest resolves no name for the Control plane or the Storage broker; those are reached over the host-opened off-network channel, so no guest-side lookup exists to retarget.
39
+
40
+ The contract carries the tagged-JSON control union and out-of-band binary stdio frames; field types and the bounded-reason error envelope live in the schema and are not restated. The schema does not encode two facts: the exec supervisor — not the guest — terminates the socket, and the runtime tier is selected by `workload_trust_profile`, not by the contract. The schema records the spawn-time environment fields; it does not pin which component enforces the strip — that actor is the host supervisor (Invariants).
41
+
42
+ ## Invariants
43
+
44
+ Each is falsifiable by the named check; cross-cutting zone, egress-mode, retention, and isolation-tier-menu properties stay in Layer 3.
45
+
46
+ 1. The guest agent is PID 1 and the container holds no process or token that outlives the session; teardown kills the process tree and destroys the cgroup (integration-test, NFR-REL-11).
47
+ 2. The exec/PTY+CDP channel is a single host-dialled socket per session; a connection from any non-host peer is dropped at accept before any frame is parsed (accept-time negative-test, NFR-SEC-76 — the accept-time enforcement of NFR-SEC-43, scoped here to the Control listener).
48
+ 3. Guest-originated code cannot reach the control/exec channel through the guest's own network stack, and a guest with in-sandbox root cannot present another session's identity (integration negative-test: guest-stack dial fails, forge-another-session fails — NFR-SEC-43).
49
+ 4. The container has exactly one outbound network route and it is the Egress trust-edge; there is no second NIC or route (IaC-policy assertion, NFR-SEC-27).
50
+ 5. Inter-sandbox reachability is disabled by default; tenant A's sandbox cannot reach tenant B's without an explicit policy (NetworkPolicy + integration-test, NFR-SEC-22).
51
+ 6. Every container carries `no-new-privileges`, cap-drop ALL with minimal add-back, seccomp BPF, read-only rootfs, user-namespace mapping (host UID 0 ≠ guest UID 0), and pids/cpu/mem cgroup limits; `docker.sock` is never mounted (admission-gate, NFR-SEC-14).
52
+ 7. The configured runtime tier matches the deployment's declared `workload_trust_profile` per the pairing matrix; a mismatch is an admission-time hard error (admission test fixture, NFR-SEC-38).
53
+ 8. A guest-spawned process inherits no host secret: the host supervisor strips the deny-pattern env set (`*_TOKEN`/`*_SECRET`/`*_PASSWORD`/`API_KEY`) at fork and injects only declared vars; no secret rides on argv (spawn-time fixture + property-test, NFR-SEC-75).
54
+ 9. Per-stream stdout/stderr over the exec channel is framed, length-prefixed, and bounded per call; on reaching the ceiling the supervisor stops forwarding, emits a truncation marker with a dropped-byte count, and never buffers unbounded guest output into host memory or the audit pipeline (red-team output-flood suite, NFR-SEC-74).
55
+ 10. Per-sandbox resource use is contained beyond the cgroup ceiling — scratch disk quota and deterministic OOM scoping (the breaching sandbox is the victim) — so one sandbox's flood holds co-resident sandboxes within the noisy-neighbour latency budget (red-team noisy-neighbour suite, NFR-SEC-46).
56
+ 11. No session-scoped secret is present in guest RAM or disk at snapshot-create time, and on resume the guest re-derives a fresh host-attested identity and reseeds entropy and unique IDs so no two guests restored from one image share a token, nonce, RNG stream, or `boot_id` (offline image-extraction scan + N-fork uniqueness test, NFR-SEC-44 + NFR-SEC-71).
57
+ 12. Every TTL/expiry decision the guest is subject to reads a monotonic clock immune to wall-clock setback, and on resume the wall clock is corrected before any time-bound check runs (red-team clock-rollback harness, NFR-SEC-48 + NFR-SEC-63 — theme [#185](https://github.com/Wide-Moat/open-computer-use/issues/185), owned by [`02-trust-boundaries.md`](../02-trust-boundaries.md)).
58
+
59
+ ## Failure modes
60
+
61
+ Each row traces to one P5 STRIDE row in [`06-threat-model.md`](../06-threat-model.md) §3.1 and repeats that row's controlling NFR; the threat narrative, rating, and regulator cell stay there. A1 (the in-sandbox guest holding root) is the reaching actor for the §3.1 rows; A3 (post-escape or host foothold) for the at-rest snapshot row.
62
+
63
+ | Trace | Reaching actor | Container-internal recovery behaviour | Controlling NFR |
64
+ |---|---|---|---|
65
+ | P2-T2 | A1 | Guest stalls or drops the host-dialled control RPC to outlive a revoke/kill. Recovery is owned by the Control/operator API ([`02-control-operator-api.md`](02-control-operator-api.md)): the F6 denylist/kill-switch check is host-side, so an unreachable channel grants the guest no new authority. | NFR-SEC-01 |
66
+ | P5-D1 | A1 | Guest exhausts node resources (fork-bomb, disk fill, memory pressure). Fail-closed via the cgroup PID/CPU/mem ceiling plus scratch quota and deterministic OOM scoping — the offender is the OOM/quota victim, co-residents hold SLO. Residual: per-session quota precision — resource-exhaustion theme [#188](https://github.com/Wide-Moat/open-computer-use/issues/188). | NFR-SEC-14 + NFR-SEC-46 + NFR-SEC-74 |
67
+ | P5-D2 | A1 | Guest floods the edge to deny outbound for itself and co-tenants. Single forward route, deny-by-default; fail-closed drops outbound if the proxy is unreachable rather than bypassing. Residual: per-session egress rate-limit unstated — resource-exhaustion theme [#188](https://github.com/Wide-Moat/open-computer-use/issues/188). | NFR-SEC-05 + NFR-SEC-27 |
68
+ | P5-I1 | A1 | Guest mounts a microarchitectural side-channel against a co-resident tenant. Per-tier posture: the shared-kernel residual is declared-not-eliminated; the reduced tier pins SMT-off, current microcode, and single-tenant scheduling for flagged sessions. Residual: a measurable cross-tenant target — side-channel theme [#183](https://github.com/Wide-Moat/open-computer-use/issues/183), [#148](https://github.com/Wide-Moat/open-computer-use/issues/148). | NFR-SEC-58 |
69
+ | P5-I3 | A1 | Guest tunnels tenant data to an allow-listed destination over the content-blind transparent pass-through rung. The container's only recovery is a single deny-by-default forward route plus a payload-independent egress-byte / destination-cardinality tripwire emitted to audit and SOAR; deep content inspection runs on the egress-wide-bump leg ([ADR-0007](../adr/0007-egress-auth-mechanism.md)), owned by the Egress trust-edge ([`06-egress-trust-edge.md`](06-egress-trust-edge.md), F8). Residual: content-blind transparent egress — theme [#182](https://github.com/Wide-Moat/open-computer-use/issues/182). | NFR-SEC-57 |
70
+ | P5-I4 | A1 | A guest-spawned process inherits a host-env secret, or a secret on argv leaks via `/proc/<pid>/cmdline`. Allowlist-only env injection with the deny-pattern strip at fork; secrets pass via env or fd, never argv. | NFR-SEC-75 + NFR-SEC-43 |
71
+ | P5-T1 | A1 | With root the guest suppresses, fabricates, or reorders the OCSF events it would author for its own in-sandbox actions. The guest is never the authoritative source: a host-side mediation layer and a not-guest-disableable runtime-monitor session author the record out of band. Residual: purely in-sandbox actions with no host-side side-effect — guest-self-audit theme [#181](https://github.com/Wide-Moat/open-computer-use/issues/181). | NFR-SEC-47 |
72
+ | P5-R1 | A1 | An in-sandbox action cannot be non-repudiably attributed because its only candidate record originates inside the guest. Out-of-band host-authored evidence supplies the record and the monotonic-clock envelope orders accepted events. Residual: the in-sandbox-evidence gap (theme [#181](https://github.com/Wide-Moat/open-computer-use/issues/181)) plus the clock-trust dependency (theme [#185](https://github.com/Wide-Moat/open-computer-use/issues/185)). | NFR-SEC-47 + NFR-SEC-48 |
73
+ | P5-I2 | A3 | A snapshot/hibernation image freezes a live Session JWT and mount handle at rest; an image read recovers a usable token before TTL. The image is taken at minimal-init before session material is layered, live token buffers are zeroized before a retained hibernate, and a single-restore guard prevents fork replay. Residual: a live secret in an off-cycle image — snapshot theme [#184](https://github.com/Wide-Moat/open-computer-use/issues/184). | NFR-SEC-44 + NFR-SEC-66 |
74
+
75
+ The host-facing default is fail-closed on every boundary the guest can pressure: an unreachable exec channel, a dropped egress route, and a failed teardown each deny authority rather than degrade open. Sandbox escape to the host kernel and the exec/PTY+CDP channel-spoof variants are MITIGATED in [`06-threat-model.md`](../06-threat-model.md) §4 (NFR-SEC-02/14, NFR-SEC-43) and are not live rows here.
76
+
77
+ ## Operational concerns
78
+
79
+ Scaling axis is per session — one container per session `[1..N]`, lifecycle bound to the session ([`05-c4-container.md`](../05-c4-container.md) §3). Capacity is governed by the host substrate and the per-sandbox cgroup ceiling (NFR-SEC-14); session-create targets ≤500 ms p99 warm-pool-hit (NFR-PERF-02), ≤2 s p99 cold-start (NFR-PERF-03), with ≤400 ms p99 on the user-space-kernel substrate (NFR-PERF-08). Compute-plane RTO for new sessions is ≤30 min with in-flight state non-durable (NFR-REL-02); stateful hibernate/resume/snapshot/fork is demonstrated end-to-end (NFR-REL-08). Cooperative shutdown is `terminationGracePeriodSeconds=30`, SIGTERM→5 s→SIGKILL, tmpdir clean ≤10 s (NFR-REL-11); teardown then runs a host-driven ordered finalizer that revokes the lease, drops the outbound route, and scrubs writable surfaces before kill, independent of guest cooperation (NFR-SEC-65). A guest that ran a session is destroyed, never re-pooled (NFR-SEC-68); a warm-pool claim re-derives a fresh host-attested identity and discards the pre-warm placeholder (NFR-SEC-69).
80
+
81
+ Config surface: the runtime tier (set by `workload_trust_profile`, validated at admission — NFR-SEC-38), the cgroup/quota ceilings (NFR-SEC-14, NFR-SEC-46), the per-stream stdio ceiling (default ≤8 MiB/stream, retunable per tier — NFR-SEC-74), the spawn-time env allowlist (NFR-SEC-75), and the exec-channel capability flags negotiated in the handshake (trace, compression — see the contract). Concurrency on the exec channel is sequential-default with opt-in parallelism (NFR-IC-05); PTY and CDP multiplex one socket per session (NFR-IC-03).
82
+
83
+ Observability: the container emits OCSF on fan-in flow F10, but the in-sandbox tool-call events are host-authored by the exec supervisor and the runtime-monitor — never the guest — per the audit contract and NFR-SEC-47 + NFR-SEC-03; the guest is not a trusted audit source for its own actions. A tier-downgrade of a running deployment fires `config.trust_profile.downgraded` within ≤30 s (NFR-SEC-39).
84
+
85
+ Shelf delta ([`05-c4-container.md`](../05-c4-container.md) §5, [`02-trust-boundaries.md`](../02-trust-boundaries.md) §8): the boundary invariants above hold on both shelves and only the substrate changes. The runtime supervisor that backs invariants 2–3, 9, and 11 is the host kernel with UDS peer-credential checks on the container tiers and the VMM with vsock on the microVM tier; the predicates (host-dialled channel, bounded stdio, no live secret in the image) do not change. The runtime-tier substrate and packaging pick is a future ADR; the FLEX-02 runtime ladder fixes the tier set, not the implementation.
86
+
87
+ ## Open questions
88
+
89
+ 1. Does the Session sandbox stay one container with internal components, or split into sub-containers once the workload-trust tier and guest-agent protocol are specified? — [#174](https://github.com/Wide-Moat/open-computer-use/issues/174).
90
+ 2. Is workload-trust tier grading (`workload_trust_profile`, AP-13) a sub-context of its own, distinct from the session-lifecycle language inside Agent Execution? — [#168](https://github.com/Wide-Moat/open-computer-use/issues/168).
91
+ 3. A measurable cross-tenant side-channel target on the shared-kernel tier ("tenant A cannot observe tenant B") is not yet an NFR scenario. — [#183](https://github.com/Wide-Moat/open-computer-use/issues/183), [#148](https://github.com/Wide-Moat/open-computer-use/issues/148).
92
+ 4. Out-of-band evidence for purely in-sandbox actions with no host-side side-effect, and host-attested binding of the OCSF source at ingestion. — [#181](https://github.com/Wide-Moat/open-computer-use/issues/181).
93
+ 5. Deterministic per-session erasure ordering and the live-secret-in-off-cycle-image residual on teardown/snapshot. — [#184](https://github.com/Wide-Moat/open-computer-use/issues/184).
@@ -0,0 +1,95 @@
1
+ <!-- SPDX-License-Identifier: FSL-1.1-Apache-2.0 -->
2
+ <!-- Copyright (c) 2025 Open Computer Use Contributors -->
3
+
4
+ ---
5
+ status: draft
6
+ last-reviewed: 2026-06-03
7
+ owner: "@Wide-Moat/architects"
8
+ applies-to: next/v1
9
+ compliance: []
10
+ threat-model: 06-threat-model.md
11
+ contract: null
12
+ adr: [0005, 0006, 0007, 0008, 0011]
13
+ ---
14
+
15
+ The sandbox's sole outbound network path: it enforces a deny-by-default destination allow-list, emits a structured deny reason, and on the legs that need it attaches the upstream authorization received over Envoy SDS so the guest carries no long-lived upstream secret on the egress leg. Audience: engineers and security reviewers wiring or auditing egress policy.
16
+
17
+ # Component-06: Egress trust-edge proxy
18
+
19
+ ## Purpose
20
+
21
+ The single outbound path for the sandbox: it resolves each destination against a deny-by-default allow-list and, on a bump-rung leg only, originates the upstream connection so it can attach the authorization received over Envoy SDS that the guest never holds ([`05-c4-container.md`](../05-c4-container.md) §3). The destination-to-rung binding is per-destination state held only at the edge, so one egress process serves a transparent-pass-through leg and an egress-wide-bump leg at once.
22
+
23
+ ## Boundaries
24
+
25
+ The intra-container view. The inbound sandbox leg, the broker backend leg, and the audit fan-in are the boundaries [`05-c4-container.md`](../05-c4-container.md) §4 names; their `F8`/`F9`/`F10` flow labels are defined in [`05-c4-container.md`](../05-c4-container.md) §4. The upstream credential arrives over Envoy SDS, an external input to the edge, not an internal OCU boundary. Token classes are owned by [`02-trust-boundaries.md`](../02-trust-boundaries.md) §8; TTLs are not repeated here.
26
+
27
+ The edge is the off-the-shelf Envoy proxy with three internal faces and one external input:
28
+
29
+ | Internal face | What it does |
30
+ |---|---|
31
+ | sandbox listener | accepts the guest's outbound request on the network-bound default route — the request carries no long-lived upstream secret; a presented scoped credential, if any, gates injection |
32
+ | upstream originator | resolves the destination, and on a bump-rung leg terminates and re-originates the TLS with the authorization attached by Envoy's `credential_injector` filter |
33
+ | audit emitter | emits an OCSF allow/deny event, denials carrying the `x-deny-reason` vocabulary |
34
+
35
+ The credential receiver is Envoy's SDS client: it receives the upstream credential over Secret Discovery Service (SDS, gRPC xDS) from the SDS source and binds it for injection on the outbound leg. The source is a static file (solo deployments) or a customer-provided SDS-compatible store (enterprise deployments); its lifecycle is the source's, per [ADR-0005](../adr/0005-egress-credential-delivery-envoy-sds.md).
36
+
37
+ Owned state: the destination allow-list (resolved-IP + SNI rules) and the per-destination rung binding (transparent pass-through vs egress-wide bump). The edge receives the credential from SDS at injection time, attaches it for the upstream leg, and drops it after the connection terminates; it holds no credential at rest and no rotation or revocation responsibility ([NFR-SEC-29](../manifesto/02-nfrs.md)). It authors no denylist and holds no kill-switch route — the denylist is the Control/operator API's; the edge reads it as a deny signal. It holds no object-store credential — the broker signs its own backend leg ([NFR-SEC-25](../manifesto/02-nfrs.md)), and the broker backend leg (F9) traverses a storage-dedicated lane on the edge, distinct from the guest egress lane ([NFR-SEC-85](../manifesto/02-nfrs.md)), with no TLS termination, so the broker-produced signature is forwarded byte-intact.
38
+
39
+ Token classes ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §8 owns the taxonomy): the edge presents the SDS-delivered authorization upstream; the guest-facing leg carries no long-lived upstream secret — at most a short-lived scoped credential the guest presents to gate injection, never the upstream key. The upstream credential is delivered by Envoy SDS, off-the-shelf and external to OCU, not an OCU-defined wire surface. The outbound leg (F8) is a network property with no wire schema by design ([NFR-SEC-27](../manifesto/02-nfrs.md)); the broker backend leg (F9) is conform on its storage-dedicated lane ([NFR-SEC-16](../manifesto/02-nfrs.md), [NFR-SEC-85](../manifesto/02-nfrs.md)). The downloadable axis reaches the edge as a broker-resolved deny signal, not a field the guest's outbound request carries ([NFR-SEC-73](../manifesto/02-nfrs.md)).
40
+
41
+ ## Invariants
42
+
43
+ Each rule holds independent of the caller and is falsifiable by the named check. Egress *posture* (the §7 rung ladder), in-transit-encryption carve-outs, and zone membership are Layer 3 properties, not invariants here.
44
+
45
+ - Every outbound connection resolves through this process; the sandbox has no route out other than F8 (network-policy IaC assertion, [NFR-SEC-27](../manifesto/02-nfrs.md)).
46
+ - A destination not matched by an allow-list rule is dropped before the TLS handshake at the SNI pre-filter, with no partial connect (integration test, [NFR-SEC-08](../manifesto/02-nfrs.md), [NFR-SEC-17](../manifesto/02-nfrs.md)).
47
+ - The proxy-owned resolver is the sole resolution authority: a guest-supplied A/AAAA cannot override it for an egress destination, and the mandatory deny-set is filtered on resolved IP at connect, never on DNS resolution (unit test per rejection class + in-guest rebind negative test, [NFR-SEC-12](../manifesto/02-nfrs.md)).
48
+ - Every denied connection is a machine-parseable object carrying the `x-deny-reason` vocabulary, never free text (schema-validation, [NFR-SEC-17](../manifesto/02-nfrs.md)).
49
+ - Injection is reachable only on the edge-originated upstream leg of a bump-rung destination; the guest→edge leg and every transparent-pass-through leg carry no upstream credential (integration test asserting no credential in the guest, [NFR-SEC-23](../manifesto/02-nfrs.md), [NFR-SEC-27](../manifesto/02-nfrs.md)).
50
+ - Injection is gated on a scoped credential the request presents, never on its network origin alone: a request reaching a bump-rung destination but presenting no scoped credential is forwarded with none attached — "inject because traffic came from sandbox X" is the forbidden anti-pattern ([ADR-0007](../adr/0007-egress-auth-mechanism.md), tightening P6-E2; bare-request negative test, [NFR-SEC-23](../manifesto/02-nfrs.md), [NFR-SEC-29](../manifesto/02-nfrs.md)).
51
+ - The injected authorization never reaches a guest-visible response surface; it is stripped before any response crosses back to the guest leg (integration test, [NFR-SEC-23](../manifesto/02-nfrs.md)).
52
+ - When the denylist names a session, the edge attaches no credential for it, independent of the credential's own validity window (integration test, [NFR-SEC-04](../manifesto/02-nfrs.md), [NFR-SEC-29](../manifesto/02-nfrs.md)).
53
+ - An outbound leg for an object the broker resolved `downloadable=false` is denied with a structured reason at every egress rung (edge integration test, [NFR-SEC-73](../manifesto/02-nfrs.md)).
54
+ - A destination tagged allow-list-only is forwarded byte-intact; the edge never terminates or re-signs the broker backend leg (integration test, [NFR-SEC-16](../manifesto/02-nfrs.md), [NFR-SEC-25](../manifesto/02-nfrs.md)).
55
+ - Denylist-propagation timing reads a monotonic clock, so a wall-clock setback cannot stall the revoke signal past its window (clock-rollback red-team harness, [NFR-SEC-48](../manifesto/02-nfrs.md), [NFR-SEC-63](../manifesto/02-nfrs.md)).
56
+
57
+ ## Failure modes
58
+
59
+ Each row traces to one P6/P5 STRIDE row in [`06-threat-model.md`](../06-threat-model.md) §3 and repeats that row's controlling NFR; the actor labels are owned by [`06-threat-model.md`](../06-threat-model.md) §2 (A1 in-sandbox guest, A3 host-side). Fail-closed is the default on every egress, injection, and deny boundary.
60
+
61
+ | Trace | Reaching actor | What goes wrong | Recovery behaviour | Controlling NFR |
62
+ |---|---|---|---|---|
63
+ | P6-R1 | A1 | A policy-violating egress attempt is later disputed and the decision, destination, and injected-or-not are not durably recorded | Emit OCSF on F10 for every allow and deny; denials carry the structured `x-deny-reason`; SNI pre-filter drops and L7 inspections both record | NFR-SEC-03 |
64
+ | P6-I1 | A1 | Content-blind exfil: the guest tunnels data to an allow-listed destination over the transparent pass-through rung (non-inspecting) | Allow-list narrows destinations; the payload-independent byte/cardinality tripwire arms at every rung; deep DLP requires the egress-wide-bump rung | NFR-SEC-57, NFR-SEC-73 |
65
+ | P6-I2 | A1 | The injected credential leaks back to the guest via an error, redirect, or reflected header at the egress-wide-bump rung | Strip injected authorization from every response surface before it crosses to the guest leg; injection only on the edge-originated leg; the credential is received from SDS at injection and never persisted at the edge | NFR-SEC-23, NFR-SEC-29 |
66
+ | P6-I3 | A3 | The bump-rung decrypt/re-encrypt segment exposes plaintext at the edge in memory or swap | The bump rung is per-destination, a single named inspection segment, TLS 1.3 on both legs; transparent-pass-through and broker legs never terminate | NFR-SEC-05, NFR-SEC-33 |
67
+ | P6-E1 | A1 | Allow-list bypass via SNI≠Host domain-fronting, CONNECT abuse, DNS rebinding, or raw-IP / non-HTTP | Deny-by-default; SNI pre-filter drop before TLS; L7 SNI/Host consistency check on the inspected leg; proxy-owned resolver | NFR-SEC-27, NFR-SEC-05, NFR-SEC-16 |
68
+ | P6-E2 | A1 | The guest forces injection toward an unintended destination via a cross-scope allow-list entry or open redirect on an allowed upstream | Gate injection on the scoped credential the request presents, never on its network origin alone ([ADR-0007](../adr/0007-egress-auth-mechanism.md)); attach only the SDS-delivered credential matching the validated destination; credential scope is set at the SDS source, so a mis-routed credential stays bounded to the scope the source supplied | NFR-SEC-29, NFR-SEC-23, NFR-SEC-73 |
69
+ | P6-E3 | A1 | The upstream needs client-mTLS / cert-pin / DPoP, which header-token injection cannot satisfy | The customer configures the SDS source to supply the client cert / PoP key, re-originated at the bump rung; a source that cannot supply it makes the destination incompatible at config time with a structured deny; a guest-resident-key workaround is refused | NFR-SEC-50 |
70
+ | P6-D1 | A1 | The edge is made unreachable by a crash, connection flood, or upstream-timeout storm, losing the sole outbound path | Fail-closed: outbound traffic drops, never bypasses; unallowed destinations dropped cheaply at the SNI pre-filter before TLS to bound handshake-exhaustion cost | NFR-SEC-46, NFR-SEC-53 |
71
+ | P6-D3 | A3 | Clock rollback at the edge defeats denylist-propagation timing | Denylist propagation reads a monotonic clock; the denylist is also checked directly on every injection, giving a non-clock revoke path | NFR-SEC-48, NFR-SEC-63 |
72
+ | P6-T1 | A3 | At the egress-wide-bump rung the edge holds plaintext between decrypt and re-encrypt; a compromised edge alters bodies undetected | The bump rung is per-destination, customer-CA-rooted, TLS 1.3 on both legs; the carve-out is a single auditable inspection point | NFR-SEC-05, NFR-SEC-33 |
73
+ | P5-D2 | A1 | The guest floods the edge with connection/request volume to deny outbound to co-tenant sessions or amplify against an upstream | Single forward proxy bounds reachable destinations; fail-closed drops rather than bypasses; per-session egress rate / connection quota | NFR-SEC-05, NFR-SEC-27 |
74
+
75
+ Residual, by [`06-threat-model.md`](../06-threat-model.md) §5 register: the transparent (non-inspected) leg stays content-blind, so P6-I1 records only metadata and P6-R1 can dispute only metadata — content-blind transparent egress, accepted-with-tier ([#182](https://github.com/Wide-Moat/open-computer-use/issues/182)). The no-credential-in-response stripping behind P6-I2, the edge-binary/config attestation behind P6-T1, and the plaintext-zeroization behind P6-I3 lack an explicit NFR ([#197](https://github.com/Wide-Moat/open-computer-use/issues/197)). SNI/Host consistency on the transparent leg behind P6-E1 is unenforced ([#198](https://github.com/Wide-Moat/open-computer-use/issues/198)). The destination-to-lease binding and per-action authz behind P6-E2 are tracked at [#187](https://github.com/Wide-Moat/open-computer-use/issues/187); the guest-resident-key schemes behind P6-E3 are declared unsupported ([#176](https://github.com/Wide-Moat/open-computer-use/issues/176)). The per-sandbox egress conn-rate / fd containment behind P6-D1 / P5-D2 is the resource-exhaustion theme — NFR-SEC-46 is the edge control and NFR-SEC-53 the sibling MCP-gateway-listener ceiling ([#188](https://github.com/Wide-Moat/open-computer-use/issues/188)). Clock-rollback behind P6-D3 is the trusted-time theme ([#185](https://github.com/Wide-Moat/open-computer-use/issues/185)). The MITIGATED P6 rows (the listener spoof, the bump-rung upstream spoof, the broker-leg tamper) live in [`06-threat-model.md`](../06-threat-model.md) §4.
76
+
77
+ ## Operational concerns
78
+
79
+ **Config surface.** The allow-list (resolved-IP + SNI rules per destination), the per-destination egress rung ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §7), the proxy-owned resolver and its deny-set (the canonical list is in [NFR-SEC-12](../manifesto/02-nfrs.md), enforced by the resolver invariant above), and the per-session egress rate / connection ceilings. DLP-ICAP is a configuration of the egress-wide-bump rung, not a separate rung ([NFR-FLEX-15](../manifesto/02-nfrs.md), [NFR-COMP-28](../manifesto/02-nfrs.md)).
80
+
81
+ **Observability.** The edge emits an OCSF event for every allow and deny on fan-in flow F10, denials carrying the `x-deny-reason`, against the audit contract ([`08-contracts.md`](../08-contracts.md) §1) and [NFR-SEC-03](../manifesto/02-nfrs.md). The payload-independent exfil tripwire ([NFR-SEC-57](../manifesto/02-nfrs.md)) raises a structured OCSF anomaly event in both postures.
82
+
83
+ **Scaling axis.** A per-host shared edge serves many co-located sessions, which makes it a shared DoS surface (P5-D2 / P6-D1); the per-session rate / fd ceiling under [NFR-SEC-46](../manifesto/02-nfrs.md) is the containment, with [NFR-SEC-53](../manifesto/02-nfrs.md) bounding the sibling MCP-gateway listener, not the edge. Whether the edge is one-per-host or one-per-deployment tracks the same instantiation question as the broker ([#175](https://github.com/Wide-Moat/open-computer-use/issues/175)).
84
+
85
+ **Rotation / lifecycle.** The edge receives the credential from SDS per-connection and drops it after use; rotation belongs to the SDS source, not the edge ([NFR-SEC-04](../manifesto/02-nfrs.md)). On sandbox teardown the host-driven finalizer drops the network-bound egress route host-side even if the guest is unresponsive ([NFR-SEC-65](../manifesto/02-nfrs.md)).
86
+
87
+ **Shelf delta** ([`05-c4-container.md`](../05-c4-container.md) §5): egress posture is a ladder by need ([`02-trust-boundaries.md`](../02-trust-boundaries.md) §7, [ADR-0007](../adr/0007-egress-auth-mechanism.md)). A deployment with no outbound need runs deny-all; one needing only unauthenticated internet runs transparent pass-through (no CA) and cannot inject; one with an upstream credential configured runs egress-wide bump — a per-deployment CA auto-generated and its public cert auto-injected into the sandbox trust store at start, attaching the credential on the edge-originated leg. The enterprise shelf points the credential at a customer-provided SDS source. The boundary properties in the Invariants section hold at every rung; the CA and the TLS-termination capability appear at the bump rung. Envoy is the forward-proxy substrate ([ADR-0006](../adr/0006-egress-forward-proxy-substrate.md)); the bump rung terminates with a leaf minted per SNI from that CA — pre-minted over a file SDS source for a config-time-enumerable allow-list, or a self-hosted SDS minting service for a non-enumerable one ([ADR-0007](../adr/0007-egress-auth-mechanism.md)).
88
+
89
+ ## Open questions
90
+
91
+ 1. Envoy's `credential_injector` filter and its OAuth2 extension carry an upstream maturity caveat — not substantial production burn-in, an unknown security posture, intended for trusted-on-both-ends paths — while a third-party LLM API is an untrusted upstream. The regulated-tier posture for this filter is deferred pending a security review ([#240](https://github.com/Wide-Moat/open-computer-use/issues/240)).
92
+ 2. ~~MITM-termination technology undecided.~~ Resolved by [ADR-0007](../adr/0007-egress-auth-mechanism.md): the bump rung terminates with a leaf minted per SNI from a per-deployment CA, served by the Envoy data plane plus a self-hosted SDS minting service; a config-time-enumerable allow-list uses pre-minted leaves over a file SDS source instead. Selection between edge-inject and a protocol broker is per upstream; v1 ships edge-inject only.
93
+ 3. SNI/Host consistency on the transparent (non-inspected) leg, where the SNI pre-filter alone misses domain-fronting — [#198](https://github.com/Wide-Moat/open-computer-use/issues/198).
94
+ 4. No-credential-in-response stripping, edge-binary/config attestation, and plaintext-zeroization for the bump rung lack an explicit NFR — [#197](https://github.com/Wide-Moat/open-computer-use/issues/197).
95
+ 5. mTLS / cert-pin / DPoP upstreams the edge cannot serve by injection, and the guest-resident-key schemes declared unsupported — [#176](https://github.com/Wide-Moat/open-computer-use/issues/176).